1

我目前正在使用 TDD 编写测试,并且遇到了一些查询。

通常在编写单元测试时,我总是习惯于每个单元测试使用 1 个断言,因为这被定义为良好实践,并且很容易看出你的测试失败的原因。

在 TDD 中,做同样的事情是否也是一种好习惯,如果是这种情况,那么使用 TDD 有效地设计 1 种方法我最终会得到超过 1 个单元测试——因为我实际上需要超过 1 个断言。

另一个问题是我实际上断言了什么?

我可以断言我认为返回对象可能是什么?

所以我必须创建返回类型(可能很复杂,有很多属性)并确保这些在断言上匹配,这在技术上可能是 1 断言。

或者另一种方法是确保我在此过程中制作的模拟实际上被称为即最小起订量我可以执行以下操作

     myServiceMock.Verify(x => x.ItemsReceived(), Times.Once());

所以我可以确保在我的模拟中只调用一次方法,这实际上被归类为断言。所以它回到原始查询,每个单元测试 1 个断言,所以我需要创建额外的单元测试以确保调用其他模拟上的其他方法。

其他人在这里做什么?

您是否断言在模拟上调用方法或返回的值是您所期望的。

真的很期待任何人对此的任何意见。

4

2 回答 2

6

我看到你的问题有不同的问题,我想谈一谈。

首先,关于每次测试一个断言。关于这是否是好的做法,有不同的想法。事实是,严格遵守它会使事情变得过于复杂。TDD 应该帮助你设计出好的和干净的代码,而不是让你死守某些原则。您可以在此处阅读 Robert Martin 的干净代码中有关此主题的信息。

其次,您是想使用模拟框架查看对象内部发生了什么,还是仅仅断言某些值取决于您正在编写的测试类型。

您可以在验证状态的测试或验证行为的测试中对测试进行分类。

  • 对于基于状态的测试,您将检查与测试相关的某些值,例如,如果我的 add 函数返回正确的值。
  • 对于基于行为的测试,您使用模拟对象来验证行为,因为使用生产代码验证结果通常不是微不足道的,例如考虑如何自动验证直接输出到调制解调器或监视器等设备的数据。

查看 Martin Fowler关于这个主题的优秀文章Mocks Aren't Stubs 。

第三,老实说,我不完全确定您所说的意思:

在 TDD 中,做同样的事情是否也是一种好习惯,如果是这种情况,那么使用 TDD 有效地设计 1 种方法我最终会得到超过 1 个单元测试——因为我实际上需要超过 1 个断言。

我假设你认为你只需要为你想要实现的新方法编写一个测试,这太疯狂了。想想实现一个除法功能。您如何确保除法正常工作以及在除以 0 的情况下会产生错误?这是不可能的。这意味着您至少需要对此方法进行两次测试。

第四,测试驱动开发中的“测试”是一个非常有偏见的术语。一般来说,人们倾向于相信在 TDD 中定义测试是为了确保代码不会被破坏,这通常是测试人员而不是开发人员的任务。但是,在 TDD 中,您应该认为单元测试正在为尚未实现的方法或类定义行为。

差异看似微不足道,但却是一个非常有力的陈述。它使您能够在实际编写单行代码之前告诉程序您的期望。想一想,让它沉入其中并尝试一下。它制造了巨大的差异。BDD 就是基于这种想法而创建的。然而,它远不止这些。在这个出色的演示文稿中,您可以从 BDD 的发明者 Dan North 那里获得更多关于 BDD 的详细信息。

这一切不仅是我对事物的看法,也是伟大的软件开发者的看法。所以,我希望它能让你对 TDD 有一个很好的看法,并帮助你继续你的旅程,

于 2013-09-03T17:19:07.047 回答
6

这是所有编写测试的人的常见问题。

在我看来(我知道还有很多其他的),一个断言每个测试的教条(1A/T)对于基本单元测试是有效的,比如1 + 1 = 2. 随着整个应用程序规模的增加,例如在集成或系统测试中,这将不再起作用。但这可能不是你的范围。

面对问题:

[TestMethod]
public void TwoAsserts()
{
    int a = 42;
    int b = 17;

    int quotient;
    int remainder;

    quotient = Math.DivRem(a, b, out remainder);

    Assert.AreEqual(2, quotient, "quotient is wrong");
    Assert.AreEqual(8, remainder, "remainder is wrong");
}

对于这两个断言,您的替代方案是什么?

使用相同的输入但不同的断言进行两个测试?肯定不是。

编写一个专门的断言方法(就像你提到的那样)来检查所有输出并在之后失败?也许。

但是您应该记住,测试应该易于理解和维护。每个阅读测试的人——包括初学者或技术不高的人——都应该清楚地看到你要测试什么以及你的输入、输出和断言是什么。

“代码的阅读频率远高于编写频率”(测试也是如此)

另外,当商断言失败时,谁在乎你是否有余数通过?这是否意味着您通过了 50%?不,就质量而言,这将是 100% 错误的。因此,请继续修复您的软件并再次运行测试。绿色的?好的!

总结:保持你的测试简单,尽可能少地使用断言,但尽可能多地使用。阻止你编写测试的一切都是邪恶的。

于 2013-09-03T17:24:48.587 回答