Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use moq to verify that a similar object was passed in as argument?

I have had a few occasions where something like this would be helpful. I have, for instance, an AccountCreator with a Create method that takes a NewAccount. My AccountCreator has an IRepository that will eventually be used to create the account. My AccountCreator will first map the properties from NewAccount to Account, second pass the Account to the repo to finally create it. My tests look something like this:

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);
}

So, what I need is something to replace It.IsAny<Account>, because that doesn't help me verify that the correct Account was created. What would be amazing is something like...

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);
}

Notice I changed It.IsAny<> to It.IsLike<> and passed in a populated Account object. Ideally, in the background, something would compare the property values and let it pass if they all match.

So, does it exist already? Or might this be something you have done before and wouldn't mind sharing the code?

like image 482
Byron Sommardahl Avatar asked Jun 30 '12 02:06

Byron Sommardahl


People also ask

What is verifiable in MOQ?

Verifiable is to enlist a Setup into a set of "deferred Verify(...) calls" which can then be triggered via mock. Verify() .

What does MOQ setup do?

Moq provides a library that makes it simple to set up, test, and verify mocks. We can start by creating an instance of the class we're testing, along with a mock of an interface we want to use.

Is MOQ open source?

The Moq framework is an open source unit testing framework that works very well with .


3 Answers

To stub out a repository to return a particular value based on like criteria, the following should work:

_repositoryStub
    .Setup(x => x.Create(
        Moq.It.Is<Account>(a => _maskAccount.ToExpectedObject().Equals(a))))
    .Returns(_account);
like image 183
Derek Greer Avatar answered Oct 12 '22 00:10

Derek Greer


The following should work for you:

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

However as it was mentioned you have to implement matching criteria.

like image 32
k0stya Avatar answered Oct 12 '22 00:10

k0stya


I have done that using the FluentAssertians library (which is much more flexible and has lot's of goodies), as in the following example:

_mockedRepository
        .Setup(x => x.Create(Moq.It.Is<Account>(actual =>
                   actual.Should().BeEquivalentTo(_account, 
                       "") != null)))
        .Returns(_account);

Note the empty argument, which is needed since this is a lambda expression which can't use default parameters.

Also note the != null expression which is just to convert it to bool so to be able to compile, and to be able to pass when it is equal, since when it is not equal then FluentAssertians will throw.


Note that this only works in newer versions of FluentAssertians, for older versions you can do a similar method described in http://www.craigwardman.com/Blogging/BlogEntry/using-fluent-assertions-inside-of-a-moq-verify

It involves using an AssertionScope as in the following code

public static class FluentVerifier
{
    public static bool VerifyFluentAssertion(Action assertion)
    {
        using (var assertionScope = new AssertionScope())
        {
             assertion();

             return !assertionScope.Discard().Any();
        }
    }
 }

And then you can do:

_mockedRepository
            .Setup(x => x.Create(Moq.It.Is<Account>(actual => 
                   FluentVerifier.VerifyFluentAssertion(() =>
                       actual.Should().BeEquivalentTo(_account, "")))))))
            .Returns(_account);
like image 38
yoel halb Avatar answered Oct 12 '22 02:10

yoel halb