为什么我的模拟设置为空?

时间:2015-04-09 23:20:52

标签: c# asp.net-mvc unit-testing moq

我刚刚开始学习单元测试和模拟。我花了一整天时间阅读不同的教程,试图找到最适合练习的教程。我已经确定Testing with a mocking framework (EF6 onwards),因为它使用EF6(现代),以及似乎是一个非常流行的模拟框架(Moq)。此外,它非常香草,并托管在MSDN网络集上。它必须是体面的,对吗?

我已经完成了示例中指定的项目,并通过测试示例运行调试器,以确保我了解正在发生的事情。我正在进行的测试如下:

[TestClass] 
public class QueryTests 
{ 
    [TestMethod] 
    public void GetAllBlogs_orders_by_name() 
    { 
        var data = new List<Blog> 
        { 
            new Blog { Name = "BBB" }, 
            new Blog { Name = "ZZZ" }, 
            new Blog { Name = "AAA" }, 
        }.AsQueryable(); 

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

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

        var service = new BlogService(mockContext.Object); 
        //test code here
        var blogs = service.GetAllBlogs(); 

        Assert.AreEqual(3, blogs.Count); 
        Assert.AreEqual("AAA", blogs[0].Name); 
        Assert.AreEqual("BBB", blogs[1].Name); 
        Assert.AreEqual("ZZZ", blogs[2].Name); 
    } 
} 

这很简单,我相信我正在理解单元测试和模拟框架。凉!我决定在实例化服务之后,通过将service.AddBlog("ADO.NET Blog", "http://blogs.msdn.com/adonet");(来自前一个示例)插入到上面的TestMethod中来执行验证自己的实验。

我希望当我走过var blogs = service.GetAllBlogs();时,博客应该包含我的新条目,但事实并非如此。它只包含data初始化中的3。

这里发生了什么?该代码不应该将博客记录插入data对象,因此在调用GetAllBlogs()时将其拉出来吗?也许我不能正确理解嘲笑的想法?

2 个答案:

答案 0 :(得分:2)

  

为什么我的模拟设置为空?

因为您没有配置( setup ),所以当您向其插入数据时,它会采取任何操作。创建模拟时,它会失去&#34;原始类中存在的所有逻辑并标记为virtual。 Moq只是覆盖了这些方法,以便以后可以将它们配置为执行任何操作(返回值,抛出等)。

当然,您可以设置Add方法将数据插回到data博客列表中:

var mockSet = new Mock<DbSet<Blog>>();
mockSet.Setup(m => m.Add<It.IsAny<Blog>()).Callback(blog => data.Add(blog));

Add上调用DbSet方法时(最好通过调用服务)已配置版本的Add将接管并将博客插入您的数据列表(Callback方法告诉M​​oq &#34;调用模拟方法时调用此代码&#34;

您还可以尝试使用CallBase参数来阻止覆盖Add。但是,这可能不起作用,因为您的DbSet不知道list存在,您很可能不得不更严重地配置它。

最后一点,一旦您的实验结晶,您应该意识到配置Add不是必要的,因为您不会通过GetAllBlogs方法检查是否添加了博客而是通过对模拟本身的验证:

mockSet.Verify(m => m.Add(It.IsAny<Blog>()), Times.Once());

答案 1 :(得分:0)

您是否尝试使用CallBase属性?

mockSet.CallBase = true;