为什么我的模拟集是空的?
Why is my mock set empty?
我刚刚开始学习单元测试和模拟。我花了一整天的时间阅读不同的教程,试图找到最好的教程来练习。我选择了 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()
时拉取它吗?也许我没有正确理解模拟的想法?
Why is my mock set empty?
因为您没有配置 (setup) 它在您向其中插入数据时采取任何操作。创建模拟时,它 "loses" 原始 class 上存在并标记为 virtual
的所有逻辑。 Moq 只是重写这些方法,以便稍后您可以配置它们来执行任何操作(return 值、抛出等)。
当然,您可以设置 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
方法在调用模拟方法时告诉 Moq "invoke this code")。
您也可以尝试使用 CallBase 参数来防止覆盖 Add
。但是,这可能行不通,因为您的 DbSet 不知道 list
存在,您很可能需要对其进行更多配置。
最后一点,一旦你的实验具体化,你应该意识到配置 Add
不是必需的,因为你不会检查博客是否是通过 GetAllBlogs
方法添加的,而是通过模拟本身的验证:
mockSet.Verify(m => m.Add(It.IsAny<Blog>()), Times.Once());
您是否尝试使用 CallBase 属性?
mockSet.CallBase = true;
我刚刚开始学习单元测试和模拟。我花了一整天的时间阅读不同的教程,试图找到最好的教程来练习。我选择了 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
.
这是怎么回事?该代码不应该将博客记录插入 data
对象,从而在调用 GetAllBlogs()
时拉取它吗?也许我没有正确理解模拟的想法?
Why is my mock set empty?
因为您没有配置 (setup) 它在您向其中插入数据时采取任何操作。创建模拟时,它 "loses" 原始 class 上存在并标记为 virtual
的所有逻辑。 Moq 只是重写这些方法,以便稍后您可以配置它们来执行任何操作(return 值、抛出等)。
当然,您可以设置 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
方法在调用模拟方法时告诉 Moq "invoke this code")。
您也可以尝试使用 CallBase 参数来防止覆盖 Add
。但是,这可能行不通,因为您的 DbSet 不知道 list
存在,您很可能需要对其进行更多配置。
最后一点,一旦你的实验具体化,你应该意识到配置 Add
不是必需的,因为你不会检查博客是否是通过 GetAllBlogs
方法添加的,而是通过模拟本身的验证:
mockSet.Verify(m => m.Add(It.IsAny<Blog>()), Times.Once());
您是否尝试使用 CallBase 属性?
mockSet.CallBase = true;