Question

This seems like a very simple task but I find it extremely hard to accomplish in Moq. I have a repository that calls a unit of work to query a random picture from a database. This query has one constraint; the random picture from the database cannot be equal to the current picture being displayed. I'm building an NUnit test for the repository and I'd like to mock the unit of work like so:

[TestFixture]
public class When_the_next_random_picture_for_TopSlidePicture_show_has_been_requested
{
    private Guid _currentPictureID;
    private Picture _randomPicture;
    private Mock<IUnitOfWork<Guid>> _unitOfWorkMock;

    [SetUp]
    public void Context()
    {
        _currentPictureID = Guid.NewGuid();
        _randomPicture = new Picture { ID = Guid.NewGuid() };
        _unitOfWorkMock = new Mock<IUnitOfWork<Guid>>();
        //TODO:  Find out how to setup and verify expression when mocking method with equality comparison in a lambda expression.
        _unitOfWorkMock.Setup(uow => uow.GetRandom<Picture>(pic => pic.ID != _currentPictureID))
            .Returns(_randomPicture);
    }

    [Test]
    public void The_PictureRepository_can_query_next_random_picture()
    {
        //Arrange
        var picRepo = new PictureRepository(_unitOfWorkMock.Object);

        //Act
        var randomPicture = picRepo.GetNextRandomPicture(_currentPictureID);

        //Assert
        _unitOfWorkMock.Verify(uow => 
            uow.GetRandom<Picture>(pic => pic.ID != _currentPictureID)
            , Times.Once());

        Assert.AreEqual(_randomPicture, randomPicture);
    }
}

In the code above, the GetRandom<Picture>(Expression<Func<Picture, bool>>) in the UnitOfWork is supposed to return any picture in the database who's Guid ID isn't equal to the current pics ID. However, Setup() method called from _unitOfWorkMock returns null regardless of _randomPicture's value. After much research I found the following procedure:

_unitOfWorkMock = new Mock<IUnitOfWork<Guid>>();
_unitOfWorkMock.Setup(uow => uow.GetRandom<Picture>(It.IsAny<Expression<Func<Picture, bool>>>()))
    .Returns(_randomPicture); 

var randomPicture = picRepo.GetNextRandomPicture(_currentPictureID);

//Assert
_unitOfWorkMock.Verify(uow => 
    uow.GetRandom<Picture>(It.IsAny<Expression<Func<Picture, bool>>>())
    , Times.Once());

This allows the test to pass. BUT, I didn't test whether the picture returned from the db has the same Guid ID of the current picture ID passed in; which is the key principle for even building the test!!!

I love the Moq framework and prefer it over all other testing tools, but this seems like a massive breach of integrity as far as a unit testing platform goes. Please, someone, inform me on what I'm not seeing clearly and show me a simple and easy way to accomplish this seemingly simple task!

Gratitude

UPDATE

Thanks to @StriplingWarrior, I was able to solve the problem! His boolean algebra was wrong, but his answer was sound ;-) I found these modifications to my above code to work:

        _unitOfWorkMock = new Mock<IUnitOfWork<Guid>>();
        _unitOfWorkMock.Setup(uow => uow.GetRandom<Picture>(It.Is<Expression<Func<Picture, bool>>>(e => TestIdMatchExpression(e))))
            .Returns(_randomPicture);

    private bool TestIdMatchExpression(Expression<Func<Picture, bool>> expr)
    {
        var func = expr.Compile();

        Assert.IsFalse(func(new Picture { ID = _referencePictureID }));

        return true;
    }

         //Assert
         _unitOfWorkMock.Verify(uow =>
             uow.GetRandom<Picture>(It.Is<Expression<Func<Picture, bool>>>(e => TestIdMatchExpression(e)))
             , Times.Once());

Thanks again @StriplingWarrior!

Was it helpful?

Solution

You should be able to use a special overload of It.Is<>() to test the expression:

It.Is<Expression<Func<Picture, bool>>>(e => TestIdMatchExpression(e))

From there you just have to figure out the best way to check the expression that gets passed in. The easiest way is probably to test the behavior: the expression should match a picture with the same guid, and reject a picture with a different one.

bool TestIdMatchExpression(Expression<Func<Picture, bool>> expr)
{
    var func = expr.Compile();
    Assert.IsTrue(func(new Picture{ID = _currentPictureID}));
    Assert.IsFalse(func(new Picture{ID = Guid.NewGuid()}));
}

OTHER TIPS

Remember, when you do unit testing of a method, you have to isolate that test, mock every external dependency including database in your case , do the test of that method for different conditions of the external dependencies

 Picture randomPictureExpected = new Picture{ ID=Guid.NewGuid()}; 
   _unitOfWorkMock.Setup(uow => uow.GetRandom<Picture>(pic=>pic.ID!=_currentPictureID))
                   .Returns(randomPictureExpected);   

and your assert would be like

var randomPictureActual = picRepo.GetNextRandomPicture(_currentPictureID);

  Assert.AreEqual (randomPictureExpected.ID, randomPictureActual.ID);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top