单元测试命名最佳实践

时间:2008-09-30 22:44:29

标签: unit-testing naming-conventions

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

之前在What are some popular naming conventions for Unit Tests?

讨论了这个问题

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

在我的测试类中,我的方法包含我正在测试的方法的名称,下划线,然后是情况和我期望发生的情况,例如: Save_ShouldThrowExceptionWithNullName()

12 个答案:

答案 0 :(得分:453)

我喜欢Roy Osherove's naming strategy,它是以下内容:

<强> [UnitOfWork_StateUnderTest_ExpectedBehavior]

它具有方法名称和结构化方式所需的所有信息。

工作单元可以像单个方法,类一样小,也可以像多个类一样大。它应代表在此测试用例中要测试的所有内容并受到控制。

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

<强> [NameOfTheClassUnderTestTests]

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

答案 1 :(得分:96)

我喜欢在测试单元(即班级)之后命名测试夹具时遵循测试“应该”命名标准)。

为了说明(使用C#和NUnit):

[TestFixture]
public class BankAccountTests
{
  [Test]
  public void Should_Increase_Balance_When_Deposit_Is_Made()
  {
     var bankAccount = new BankAccount();
     bankAccount.Deposit(100);
     Assert.That(bankAccount.Balance, Is.EqualTo(100));
  }
}

为什么“应该”

我发现它迫使测试编写者用一句话来命名测试,这句话应该是[应该[在某种状态] [之后/之前/之后] [动作发生]“

是的,写“应该”到处都会有点重复,但正如我所说,它迫使作者以正确的方式思考(这对新手来说也是好事)。另外,它通常会产生可读的英语测试名称。

更新

我注意到Jimmy Bogard也是'should'的粉丝,甚至还有一个名为Should的单元测试库。

更新(4年后......)

对于那些感兴趣的人,我的命名测试方法多年来不断发展。上面描述的模式的一个问题是,一眼就看不出哪种方法正在测试中。对于OOP,我认为使用测试方法启动测试名称更有意义。对于设计良好的类,这应该导致可读的测试方法名称。我现在使用类似于<method>_Should<expected>_When<condition>的格式。显然,根据上下文,您可能希望将“应该/何时”动词替换为更合适的内容。例: Deposit_ShouldIncreaseBalance_WhenGivenPositiveValue()

答案 2 :(得分:74)

我喜欢这种命名方式:

OrdersShouldBeCreated();
OrdersWithNoProductsShouldFail();

等等。 对于非测试者来说,问题非常清楚。

答案 3 :(得分:48)

Kent Beck建议:

  • 每个'单位'一个测试夹具(程序类)。测试装置本身就是课程。测试夹具名称应为:

    [name of your 'unit']Tests
    
  • 测试用例(测试夹具方法)的名称如下:

    test[feature being tested]
    

例如,拥有以下课程:

class Person {
    int calculateAge() { ... }

    // other methods and properties
}

测试夹具将是:

class PersonTests {

    testAgeCalculationWithNoBirthDate() { ... }

    // or

    testCalculateAge() { ... }
}

答案 4 :(得分:16)

班级名称。对于测试夹具名称,我发现“测试”在许多领域的普遍存在的语言中非常普遍。例如,在工程域中:StressTest,在化妆品域中:SkinTest。很抱歉不同意肯特,但在我的测试装置中使用“测试”(StressTestTest?)令人困惑。

“单位”在域中也经常使用。例如。 MeasurementUnit。名为MeasurementUnitTest的类是“Measurement”或“MeasurementUnit”的测试吗?

因此,我喜欢为我的所有测试类使用“Qa”前缀。例如。 QaSkinTestQaMeasurementUnit。它永远不会与域对象混淆,并且使用前缀而不是后缀意味着所有测试夹具在视觉上共存(如果您的测试项目中有假货或其他支持类,则非常有用)

<强>命名空间即可。我在C#中工作,并且我将测试类保持在与他们正在测试的类相同的命名空间中。它比拥有单独的测试命名空间更方便。当然,测试类属于不同的项目。

测试方法名称。我喜欢命名我的方法WhenXXX_ExpectYYY。它使前提条件清晰,并有助于自动化文档(la TestDox)。这类似于Google测试博客上的建议,但更多地分离了前提条件和期望。例如:

WhenDivisorIsNonZero_ExpectDivisionResult
WhenDivisorIsZero_ExpectError
WhenInventoryIsBelowOrderQty_ExpectBackOrder
WhenInventoryIsAboveOrderQty_ExpectReducedInventory

答案 5 :(得分:10)

我使用 Given-When-Then 概念。 看看这篇简短的文章http://cakebaker.42dh.com/2009/05/28/given-when-then/。文章根据BDD描述了这个概念,但您也可以在TDD中使用它而不做任何更改。

答案 6 :(得分:8)

请参阅: http://googletesting.blogspot.com/2007/02/tott-naming-unit-tests-responsibly.html

对于测试方法名称,我个人觉得使用详细和自我记录的名称非常有用(与Javadoc评论一起进一步解释测试正在做什么)。

答案 7 :(得分:7)

我认为最重要的事情之一是在您的命名约定中保持一致(并与您团队中的其他成员达成一致)。很多时候,我看到在同一个项目中使用了大量不同的约定。

答案 8 :(得分:6)

我最近提出了以下惯例来命名我的测试,他们的类和包含项目,以便最大化他们的描述:

假设我正在 MyApp.Serialization 命名空间中的项目中测试 Settings 类。

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

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

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

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

MyApp.Serialization.Tests.IfSettings.CanSaveStrings

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

当然,在英语中,名词“Tests”与动词“tests”相同是有用的。

在命名测试时,您的创造力没有限制,因此我们可以为他们获得完整的句子标题。

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

示例包括:

  • 检测(例如,DetectsInvalidUserInput)
  • 投掷(例如ThrowsOnNotFound)
  • Will(例如WillCloseTheDatabaseAfterTheTransaction)

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

后者可以节省我的击键次数并更准确地描述我在做什么,因为我不知道, 测试行为是否存在,但我正在测试< strong> if

[修改

现在使用上面的命名约定后,我发现,使用接口时, If 前缀可能会造成混淆。碰巧的是,测试类 IfSerializer.cs 看起来非常类似于“打开文件选项卡”中的接口 ISerializer.cs 。 当在测试,被测试的类及其接口之间来回切换时,这会非常烦人。因此,我现在选择而不是如果作为前缀。

此外我现在使用 - 仅用于我的测试类中的方法,因为它在其他任何地方都不被认为是最佳实践 - “_”用于分隔我的测试方法名称中的单词,如下所示:

  • [测试] public void detected_invalid_User_Input()*

我发现这更容易阅读。

[结束编辑]

我希望这会产生更多的想法,因为我认为命名测试非常重要,因为它可以为您节省大量时间,否则这些时间将用于尝试了解测试正在做什么(例如,在恢复项目之后延长间隙)。

答案 9 :(得分:2)

在VS + NUnit中,我通常在项目中创建文件夹,将功能测试组合在一起。然后我创建单元测试夹具类,并在我正在测试的功能类型之后命名它们。 [Test]方法按Can_add_user_to_domain

的方式命名
- MyUnitTestProject   
  + FTPServerTests <- Folder
   + UserManagerTests <- Test Fixture Class
     - Can_add_user_to_domain  <- Test methods
     - Can_delete_user_from_domain
     - Can_reset_password

答案 10 :(得分:2)

我应该补充一点,将测试保存在同一个软件包中,但是在测试源的并行目录中,一旦准备好部署它就可以消除代码的膨胀,而不必进行一堆排除模式。

我个人喜欢"JUnit Pocket Guide"中描述的最佳做法......很难打败JUnit的合着者写的一本书!

答案 11 :(得分:0)

类Foo的测试用例的名称应该是FooTestCase或类似的东西(FooIntegrationTestCase或FooAcceptanceTestCase) - 因为它是一个测试用例。有关标准命名约定,如测试,测试用例,测试夹具,测试方法等,请参阅http://xunitpatterns.com/