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!