模拟方法在模拟对象中调用OF属性

时间:2012-04-24 19:09:29

标签: c# unit-testing moq

我正在使用工作单元模式和我的数据层。

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

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

这与我的代码库一样正常;但是,我遇到了测试这个问题 在我的服务层。

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

(测试)使用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());
}

测试抛出一个异常,说result1(和result2)为null。我意识到这是因为我没有直接实例化属性。但我想知道是否有办法不必模拟模拟内部的属性。如果没有Moq那么可能还有其他一些模拟框架?

2 个答案:

答案 0 :(得分:3)

不,Moq不会帮助你。你必须手动设置它们(虽然你也可以嘲笑它们):

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

请注意,您现在必须.Setup GetAllclass1Mock class2Mock class1Mock .Setup(c => c.GetAll()) .Returns(new [] { new Class1 {...} }.AsQueryable()); {/ 1}}

{{1}}

如果你希望对你的嘲讽有这种控制,那么恐怕没有捷径可走。

注意:即使它对您的情况没有帮助(因为您希望直接控制模拟),AutoFixture with Moq绝对值得在类似情况下查看。

答案 1 :(得分:0)

工作单元模式的巨大优势在于它从消费者那里抽象出数据源,让您决定如何在测试中实现它。

你可以选择去模拟路由,你已经避开了每个测试的一些配置开销;或者您可以创建一个实现您的工作单元的具体类,并将其用作有状态测试double。

根据我的经验,测试感觉与测试双重方法不同 - 测试并不关心使用工作单元的次数或顺序,而是关注最终结果。