命名单元测试类和测试方法的最佳实践是什么?

这在之前的SO中讨论过,在什么是单元测试的一些流行命名约定?

我不知道这是否是一种非常好的方法,但目前在我的测试项目中,我在每个生产类和测试类之间都有一对一的映射,例如Product和ProductTest。

在我的测试类中,我有我正在测试的方法的名称,一个下划线,然后是情况和我期望发生的事情,例如Save_ShouldThrowExceptionWithNullName()。


当前回答

我用“给定时”的概念。 看看这篇短文http://cakebaker.42dh.com/2009/05/28/given-when-then/。本文从BDD的角度描述了这个概念,但是您也可以在TDD中使用它,而不需要进行任何更改。

其他回答

我最近提出了以下约定来命名我的测试,它们的类和包含项目,以最大化它们的描述符:

假设我在MyApp的一个项目中测试设置类。序列化的名称空间。

首先,我将使用MyApp.Serialization.Tests名称空间创建一个测试项目。

在这个项目和命名空间中,我将创建一个名为IfSettings的类(保存为IfSettings.cs)。

假设我正在测试SaveStrings()方法。我将测试命名为CanSaveStrings()。

当我运行这个测试时,它将显示以下标题:

MyApp.Serialization.Tests.IfSettings.CanSaveStrings

我认为这很好地告诉了我,它在测试什么。

当然,在英语中名词“Tests”和动词“Tests”是一样的,这是很有用的。

在命名测试时,你的创造力是没有限制的,这样我们就可以得到完整的句子标题。

通常测试名称必须以动词开头。

例子包括:

检测(例如DetectsInvalidUserInput) 抛出(例如ThrowsOnNotFound) Will(例如WillCloseTheDatabaseAfterTheTransaction)

etc.

另一个选择是用“that”而不是“if”。

后者虽然节省了我的击键,但更准确地描述了我正在做的事情,因为我不知道,测试的行为是否存在,但我正在测试它是否存在。

(编辑)

在使用上述命名约定一段时间后,我发现,在处理接口时,If前缀可能令人困惑。恰好,测试类IfSerializer.cs看起来与“打开文件选项卡”中的isserializer .cs接口非常相似。 当在测试、被测试的类和它的接口之间来回切换时,这会非常烦人。因此,我现在将选择That而不是If作为前缀。

此外,我现在只对我的测试类中的方法使用“_”来分隔我的测试方法名称中的单词,因为它在其他任何地方都不是最佳实践:

[Test] public void detects_invalid_User_Input()

我觉得这个更容易读。

(结束编辑)

我希望这能产生更多的想法,因为我认为命名测试非常重要,因为它可以为您节省大量时间,否则您将花费大量时间试图理解测试正在做什么(例如,在长时间中断后恢复项目)。

更新(2021年7月)

距离我最初的答案(将近12年)已经有一段时间了,在这段时间里,最佳实践发生了很大变化。因此,我倾向于更新自己的答案,并为读者提供不同的命名策略。

许多评论和回答指出,我在最初的回答中提出的命名策略不抵抗重构,最终导致名称难以理解,我完全同意这一点。

在过去的几年里,我最终使用了一种更易于理解的命名模式,其中测试名称描述了我们想要测试的内容,如Vladimir Khorikov所描述的那样。

一些例子是:

Add_credit_updates_customer_balance Purchase_without_funds_is_not_possible Add_affiliate_discount

但正如您所看到的,这是一个非常灵活的模式,但最重要的是,阅读名称就知道测试是关于什么,而不包括可能随着时间变化的技术细节。

要命名项目和测试类,我仍然坚持最初的答案模式。

原答案(2009年10月)

我喜欢Roy Osherove的命名策略。是这样的:

[UnitOfWork_StateUnderTest_ExpectedBehavior]

它以结构化的方式包含了方法名所需的所有信息。

工作单元可以小到一个方法、一个类,也可以大到多个类。它应该表示在这个测试用例中要测试的所有东西,并且这些东西都在控制之下。

对于程序集,我使用典型的.Tests结尾,我认为这是相当普遍的,对于类也是如此(以Tests结尾):

[名称的类UnderTestTests]

以前,我使用Fixture作为后缀而不是Tests,但我认为后者更常见,然后我改变了命名策略。

我应该补充一点,将您的测试放在同一个包中,但位于与被测试的源代码并行的目录中,一旦您准备好部署它,就可以消除代码的膨胀,而不必执行一堆排除模式。

我个人喜欢“JUnit Pocket Guide”中描述的最佳实践……很难有一本书比JUnit!

看到的: http://googletesting.blogspot.com/2007/02/tott-naming-unit-tests-responsibly.html

对于测试方法名称,我个人认为使用详细的和自文档化的名称非常有用(以及进一步解释测试正在做什么的Javadoc注释)。

我用“给定时”的概念。 看看这篇短文http://cakebaker.42dh.com/2009/05/28/given-when-then/。本文从BDD的角度描述了这个概念,但是您也可以在TDD中使用它,而不需要进行任何更改。