1

我将工作单元模式与我的数据层一起使用。

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

(测试)使用起订量

[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)为空。我意识到这是因为我没有直接实例化属性。但我想知道是否有一种方法不必也模拟模拟内部的属性。如果不使用 Moq,那么可能还有其他一些模拟框架?

4

2 回答 2

3

不,起订量在这里帮不了你。您必须手动设置它们(尽管您也可以模拟它们):

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

请注意,您现在必须.SetupGetAllonclass1Mock和做class2Mock

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

如果你想对你的模拟进行这种控制,恐怕没有捷径可走。

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

于 2012-04-24T19:59:32.600 回答
0

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

您可以选择走模拟路线,因为您已经避开了每次测试的一些配置开销;或者您可以创建一个具体的类来实现您的工作单元并将其用作有状态的测试替身。

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

于 2012-04-25T01:55:38.363 回答