Matt Phillips
Matt Phillips

Reputation: 11499

Mocking method calls OF properties in a mock object

I'm using the Unit Of Work Pattern with my data layer.

public interface IUnitOfWork{
    IRepository<Class1> Class1s {get;}
    IRepository<Class2> Class2s {get;}
    ...
}

public interface IRepository<T> where T:class{
    IQueryable<T> GetAll();
}

This is working as expected with my codebase; however, I'm having issues testing this in my service layer.

public class SomeService{
    private readonly IUnitOfWork uow;
    public SomeService(IUnitOfWork u){
        uow = u;
    }

    public IEnumerable<ViewModel1> GetViewModel(){
        var result1 = uow.Class1s.GetAll();
        var result2 = uow.Class2s.GetAll();
        var query = from r1 in result1
                    from r2 in result2
                       where r1.key == r2.key
                       select new ViewModel1{...};
        return result;
    }
}

(The test) using Moq

[Test]
public void TestMethod(){
    var uow = new Mock<IUnitOfWork>();
    uow.Setup(u => u.Class1s.GetAll()).Returns(new []{ new Class1{...}}.AsQueryable());
    uow.Setup(u => u.Class2s.GetAll()).Returns(new []{ new Class2{...}}.AsQueryable());
    var service = new SomeService(uow.Object);
    var result = service.GetViewModel();
    Assert.AreEqual(1,result.Count());
}

The test is throwing an exception saying that result1 (and result2) are null. I realized this was because I'm not directly instantiating the properties. But I was wondering if there was a way to not have to also mock the properties inside of the mock. If not with Moq then maybe some other mocking framework?

Upvotes: 1

Views: 1427

Answers (2)

bryanbcook
bryanbcook

Reputation: 17983

The great advantage to the unit of work pattern is that it abstracts the data source from its consumers, leaving you to decide how to implement it in the tests.

You can choose to go the mocking route, which as you've eluded is a bit of configuration overhead per test; or you can create a concrete class that implements your unit of work and use it as a stateful test double.

In my experience, the tests feel different with the test double approach - the tests don't care how many times or the order which the Unit of Work is used but focus on the end-result.

Upvotes: 0

k.m
k.m

Reputation: 31444

No, Moq won't help you here. You'll have to set them manually (although you can mock them aswell):

var class1Mock = new Mock<IRepository<Class1>>();
var class2Mock = new Mock<IRepository<Class2>>();
var uow = new Mock<IUnitOfWork>();
uow.Setup(u => u.Class1).Returns(class1Mock.Object);
uow.Setup(u => u.Class2).Returns(class2Mock.Object);

Note that you'll now have to do .Setup for GetAll on class1Mock and class2Mock:

class1Mock
    .Setup(c => c.GetAll())
    .Returns(new [] { new Class1 {...} }.AsQueryable());

If you want to have this kind of control over your mocks, there's no shortcuts I'm afraid.

Note: even though it wont help in your case (since you want direct control over mocks), AutoFixture with Moq is definitely worth checking out in similar scenarios.

Upvotes: 3

Related Questions