moq框架的真正目的

时间:2016-08-17 10:24:23

标签: c# unit-testing nunit moq

我被要求使用Moq框架编写单元测试。关于如何在c#中编写Moq测试,我还是比较新的。

我正在浏览MSDN link

这就是我现在正在做的事情,因为我们在存储库

上使用依赖注入
    //Repository
public interface IRepo
{
    IQueryable<MyModel> GetById( long userId );
}

public class Repo : BaseManager, IRepo
{
    public Repo(myDbContext context)
    {
        dbContext = context; //dbContext is from BaseManager class
    } 
    public IQueryable<MyModel> GetById( long userId )
    {
        return dbContext.MyModel.Where(x => x.IsActive && x.UserId == userId );
    }
}

//Test class
public class Test 
{
    Mock<DbSet<MyModel>> mockSet;
    Mock<myDbContext> mockContext;
    Mock<IRepo> mockRepository;

    [TestInitialize]
    public void Setup()
    {
        var data = new List<MyModel>{
            //3 records
        }.AsQueryable();

        var mockSet = new Mock<DbSet<MyModel>>();
        mockSet.As<IQueryable<MyModel>>().Setup(m => m.Provider).Returns(data.Provider);
        mockSet.As<IQueryable<MyModel>>().Setup(m => m.Expression).Returns(data.Expression);
        mockSet.As<IQueryable<MyModel>>().Setup(m => m.ElementType).Returns(data.ElementType);
        mockSet.As<IQueryable<MyModel>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());

        var mockContext = new Mock<myDbContext>();
        mockContext.Setup(c => c.MyModel).Returns(mockSet.Object);

        mockRepository = new Mock<IRepo>();
        mockRepository.Setup(m => m.GetById(It.IsAny<long>())).Returns(data); //Here the GetById method is set to return all 3 records set in data object. 
    }

    [TestMethod]
    public void Test_Mock_For_Nothing()
    {
        var controller = new MyController(mockRepository.Object);
        var result = controller.GetById(1); //this will call GetById method in the repository

        Assert.AreEqual(result.Count(), 1);//This will fail as we will get count as 3
    }
}

因此,尽管我模拟了上下文和存储库,但存储库中的逻辑从未执行过。因为GetById方法会根据虚拟数据直接返回3条记录的结果。

我希望根据存储库方法中的逻辑过滤出虚拟数据。 Moq可以实现吗?

在没有执行存储库代码时使用Moq框架的真正目的是什么?

3 个答案:

答案 0 :(得分:3)

鉴于您已经模拟了您的存储库,而没有看到Controller逻辑,我不确定您为什么需要模拟dbContext。但是,有效地使用此测试,您正在测试Controller逻辑而不是存储库,因为您已经模拟了存储库以及从存储库中的GetById返回的内容。

如果您希望测试存储库中的过滤器逻辑,则需要模拟dbContext(就像您所做的那样)并在测试中创建一个新的具体Repository实例并测试从对GetById的调用返回的数据

所以你模拟dbContext.MyModel,返回你的三个项目,让Where调用执行过滤。

关于使用模拟框架有很多有用的信息,但是每个人对于你应该测试什么以及你应该在单个单元测试中测试的小单元有不同的意见,经验和个人偏好是关键在这里。

答案 1 :(得分:1)

就测试而言,我认为使用模拟框架甚至进行此测试几乎没有什么好处。我的想法是:

1)如果您有一个存储库,请编写集成测试,因为您要证明您正在从数据库/ Web服务等返回数据

2)在您想要测试某些业务逻辑/行为的情况下使用Moq或RhinoMocks

答案 2 :(得分:0)

使用单元测试,您尝试测试/强化您的业务逻辑。在您的存储库中不应该是任何BL(Businesslogic)。使用你的MOCK框架你禁用认为你不想测试。 - &GT;存储库=访问数据。 通过这种方式,您可以更改获取数据(存储库)的方式,而无需对Businesslogic / UnitTests进行任何更改:)

PS:如果您想测试您的存储库或更多,您应该针对集成测试甚至是端到端测试。