0

我正在使用最小起订量,似乎无法让我的单元测试通过看似简单的模拟场景。

Product p = new Product();
var rep = new Mock<IProductRepository>();
rep.Expect(x => x.GetProductById(1)).Returns(p);
p = rep.Object.GetProductById(1);
Assert.AreEqual(1, p.ProductId);  //Assert.AreEqual failed. Expected:<1>. Actual:<0>.

关于我做错了什么的任何指示?我的单元测试报告:-

Assert.AreEqual 失败。预期:<1>。实际:<0>。

4

6 回答 6

4

我认为你错过了如何在测试中使用模拟对象的重点......

您正在做的是模拟 ProductRepository 对象,同时对其进行测试。这没有多大意义;你不应该模拟你正在测试的对象。

假设您有一个要测试的类 ProductService,它依赖于另一个类 IProductRepository。当您测试 ProductService 时,您需要模拟依赖项 IProductRepository。这使您可以完全控制被测类与其(模拟)依赖项之间的交互。

当您这样做时,您的断言将基于您期望被测类 ProductService 执行的操作。例如,如果您使用类似的方法调用 ProductService productService.GetProductById(1),您将期望 ProductService 对象使用正确的参数调用其 IProductRepository 方法一次:repository.GetProductById(1)。您可能还期望 ProductService 返回 IProductRepository 给它的相同对象。无论存储库做什么,这都是 ProductService 的责任。

话虽如此,您的测试可能看起来更像这样:

//Arrange
int testId = 1;
var fakeProduct = new Product{ Id = testId };
var mockRepo = new Mock<IRepository>();
var productService = new ProductService(mockRepo);
mockRepo.Expect(repo => repo.GetProductById(testId)).Returns(fakeProduct);

//Act
Product returnedProduct = productService.GetProductById(testId);

//Assert
mockRepo.Verify(repo => repo.GetProductById(testId), TimesExactly(1));
Assert.AreEqual(returnedProduct.Id, fakeProduct.Id);

我的语法可能不正确,但希望该示例能够跨越几点:

  1. 不要模拟被测系统
  2. 模拟依赖项
  3. 将您的断言基于被测系统的职责,而不是依赖关系
于 2009-11-29T22:30:19.640 回答
3

您正在创建一个对象,将该对象设置为方法的返回值,然后检查模拟是否正在更改对象,模拟不打算做的事情您基本上是在这样做:

Product getProductById(Product p) { return p; }
...
Product p = new Product();
Assert.AreEqual(1, getProductById(p).ProductID );

创建新产品时:

Product p = new Product();

我猜默认ProductID是0,所以这句话:

 getProductById(p).ProductID

显然会返回 0。

我也是在这里嘲笑的新手,但我不明白你的意思。你想测试什么?Product 类、ProductRepository 或它们之间的交互?这是首先要考虑的事情。

于 2009-01-29T07:41:54.663 回答
1

我正在查看您的代码,但看起来您并不真正知道您要实现的目标。在编写任何测试之前,请始终提出以下问题:“在这里,我想证明什么?” 将返回您创建的产品,但其 ID 将是默认值 (0);这是预期的行为,即模拟框架运行良好。

测试替身(模拟、存根、伪造、间谍等)在测试中用于为被测类提供合作者。它们将有趣的值输入到被测类或接收来自被测类的调用——它们不是测试的焦点。

您的测试当前正在断言测试替身本身返回的值。据我了解,要么您是在寻求上下文无关代码片段的帮助(片段本身只是一个示例,而不是测试本身),要么它是毫无意义的真实测试代码。

我见过很多人将自己与模拟框架联系在一起。 这就是为什么,首先,我建议您自己手写测试替身。这有助于您了解对象之间的交互,并更清楚地了解您希望测试的内容。再次,这又回到了“我在这里要证明什么?”的问题。

一旦你了解了如何使用手动测试替身来实现目标,你就可以毕业到模拟框架。

于 2009-11-29T21:52:27.433 回答
0

我会支持 Gishu re 的观点:产品初始化。除非 IProductRepository 的默认行为是返回 ProductId 为“1”引用的产品,否则您的测试将失败。

而且,我可以补充一下,这种失败似乎是明智的行为。我认为您希望 ProductRepository 在初始化时为空。

于 2009-01-29T06:26:28.280 回答
0

没有完全错过重点,Mocking 并非微不足道。

在你的情况下,你有一个IProductRepository,我想,应该持有Products。我假设默认情况下Products不会将其添加到ProductRepositort(根据我之前的帖子),并且我还假设为了引用 a Product,它必须具有 a productId(顺便说一句,您确实应该通过mutator进行变异)。

如果Product从您的ProductRepository. s 向其添加默认标识符(推荐)或在将其添加到.ProductProductRepostoryProductProductProductRepository

于 2009-01-29T06:51:29.883 回答
0

在设置期望 - 返回 (p) 时,您将 Product 实例 p 用作“预期值”一次,然后使用相同的引用来存储实际调用的返回值。

至于 Assert 失败, new Product() 是否将其 ProductId 初始化为 1。似乎将其设置为默认值 0 - 因此出现错误。

我认为 Mock 框架正在运行。

于 2009-01-29T06:11:14.440 回答