Как использовать moq для проверки того, что аналогичный объект был передан в качестве аргумента? - программирование

Как использовать moq для проверки того, что аналогичный объект был передан в качестве аргумента?

У меня было несколько случаев, когда что-то вроде этого было бы полезно. Я имею, например, AccountCreator с Create методом, который принимает NewAccount. Мой AccountCreator имеет IRepository, который в конечном итоге будет использоваться для создания учетной записи. Мой AccountCreator сначала отобразит свойства от NewAccount до Account, второй передайте Account в репо, чтобы, наконец, создать его. Мои тесты выглядят примерно так:

public class when_creating_an_account
{
    static Mock<IRepository> _mockedRepository;
    static AccountCreator _accountCreator;
    static NewAccount _newAccount;
    static Account _result;
    static Account _account;

    Establish context = () =>
        {
            _mockedRepository = new Mock<IRepository>();
            _accountCreator = new AccountCreator(_mockedRepository.Object);

            _newAccount = new NewAccount();
            _account = new Account();

            _mockedRepository
                .Setup(x => x.Create(Moq.It.IsAny<Account>()))
                .Returns(_account);
        };

    Because of = () => _result = _accountCreator.Create(_newAccount);

    It should_create_the_account_in_the_repository = () => _result.ShouldEqual(_account);
}

Итак, мне нужно что-то заменить It.IsAny<Account>, потому что это не помогает мне проверить правильность создания учетной записи. Что было бы удивительно, это что-то вроде...

public class when_creating_an_account
{
    static Mock<IRepository> _mockedRepository;
    static AccountCreator _accountCreator;
    static NewAccount _newAccount;
    static Account _result;
    static Account _account;

    Establish context = () =>
        {
            _mockedRepository = new Mock<IRepository>();
            _accountCreator = new AccountCreator(_mockedRepository.Object);

            _newAccount = new NewAccount
                {
                    //full of populated properties
                };
            _account = new Account
                {
                    //matching properties to verify correct mapping
                };

            _mockedRepository
                .Setup(x => x.Create(Moq.It.IsLike<Account>(_account)))
                .Returns(_account);
        };

    Because of = () => _result = _accountCreator.Create(_newAccount);

    It should_create_the_account_in_the_repository = () => _result.ShouldEqual(_account);
}

Обратите внимание, что я изменил It.IsAny<> на It.IsLike<> и прошел в заполненном объекте Account. В идеале, в фоновом режиме, что-то сравнивало бы значения свойств и пропускало бы их, если они все совпадают.

Итак, он уже существует? Или это может быть что-то, что вы делали раньше и не хотели бы делиться кодом?

4b9b3361

Ответ 1

Чтобы заглушить репозиторий, чтобы вернуть определенное значение, основанное на подобных критериях, должно работать следующее:

_repositoryStub
    .Setup(x => x.Create(
        Moq.It.Is<Account>(a => _maskAccount.ToExpectedObject().Equals(a))))
    .Returns(_account);

Ответ 2

Для вас должно работать следующее:

Moq.It.Is<Account>(a=>a.Property1 == _account.Property1)

Однако, как уже было сказано, вы должны выполнить критерии соответствия.

Ответ 3

Я не смог найти ничего, что точно соответствует тому, что описано в вопросе. В то же время лучший способ найти проверку объектов, переданных в качестве аргументов для издевающихся методов (без роскоши референциального равенства), представляет собой комбинацию Callback и шаблона ожидаемого объекта для сравнения фактического с ожидаемым объект:

public class when_creating_an_account
{
    static Mock<IRepository> _mockedRepository;
    static AccountCreator _accountCreator;
    static NewAccount _newAccount;
    static Account _result;
    static Account _expectedAccount;
    static Account _actualAccount;

    Establish context = () =>
        {
            _mockedRepository = new Mock<IRepository>();
            _accountCreator = new AccountCreator(_mockedRepository.Object);

            _newAccount = new NewAccount
                {
                    //full of populated properties
                };
            _expectedAccount = new Account
                {
                    //matching properties to verify correct mapping
                };

            _mockedRepository
                .Setup(x => x.Create(Moq.It.IsAny<Account>(_account)))
                //here, we capture the actual account passed in.
                .Callback<Account>(x=> _actualAccount = x) 
                .Returns(_account);
        };

    Because of = () => _result = _accountCreator.Create(_newAccount);

    It should_create_the_account_in_the_repository = 
        () => _result.ShouldEqual(_account);

    It should_create_the_expected_account = 
        () => _expectedAccount.ToExpectedObject().ShouldEqual(_actualAccount);
}

Ожидаемый шаблон объекта велик, но его сложно реализовать на С#, поэтому я использую библиотеку, которая обрабатывает все, что для меня. https://github.com/derekgreer/expectedObjects

В моем последнем наблюдении рассматриваются свойства в фактической учетной записи, прошедшей мимо, и сравнивается каждый с одним и тем же свойством на моем "ожидаемом объекте". Таким образом, у меня нет огромного списка проверок свойств, и у меня нет тонких тестовых наблюдений.