我应该更改单元测试的命名约定吗?

时间:2009-06-19 15:13:37

标签: unit-testing tdd naming-conventions bdd

我目前使用一个简单的约定进行单元测试。如果我有一个名为“EmployeeReader”的类,我创建一个名为“EmployeeReader.Tests的测试类。然后我在测试类中为类创建所有测试,其名称如下:

  • Reading_Valid_Employee_Data_Correctly_Generates_Employee_Object
  • Reading_Missing_Employee_Data_Throws_Invalid_Employee_ID_Exception

等等。

我最近一直在阅读BDD中使用的different type of naming convention。我喜欢这个命名的可读性,最终得到一个类似的测试列表:

  • When_Reading_Valid_Employee(fixture)
    • Employee_Object_Is_Generated(方法)
    • Employee_Has_Correct_ID(方法)
  • When_Reading_Missing_Employee(灯具)
    • An_Invalid_Employee_ID_Exception_Is_Thrown(方法)

等等。

有没有人使用这两种命名方式?您能否提供任何建议,优惠,缺点,陷阱等,以帮助我决定是否为我的下一个项目进行切换?

7 个答案:

答案 0 :(得分:6)

我一直在使用的命名约定是:

  

functionName_shouldDoThis_whenThisIsTheSituation

例如,这些是堆栈'pop'函数的一些测试名称

  

pop_shouldThrowEmptyStackException_whenTheStackIsEmpty

     

pop_shouldReturnTheObjectOnTheTopOfTheStack_whenThereIsAnObjectOnTheStack

答案 1 :(得分:3)

你的第二个例子(每个逻辑“任务”都有一个夹具,而不是每个类的一个)具有的优点是你可以为每个任务设置不同的SetUp和TearDown逻辑,从而简化你的各个测试方法并使它们更多可读的。

您不需要将其中一个作为标准来解决。我们使用两者的混合,取决于我们必须为每个类测试多少个不同的“任务”。

答案 2 :(得分:2)

我觉得第二个更好,因为它使你的单元测试对其他人更具可读性,因为长行会使代码看起来更难以阅读或使其更难以浏览。如果您仍然觉得测试的内容有任何歧义,您可以添加注释以澄清这一点。

答案 3 :(得分:1)

您引用的第二个命名约定背后的部分原因是您正在同时创建测试和行为规范。您可以建立事物发生的上下文以及在该上下文中实际发生的事情。 (根据我的经验,观察/测试方法通常以“should_”开头,因此您获得标准的“When_the_invoicing_system_is_told_to_email_the_client”,“should_initiate_connection_to_mail_server”格式。)

有些工具可以反映您的测试装置并输出格式良好的html规格表,剥离下划线。您最终会获得与实际代码同步的人类可读文档(只要您保持测试覆盖率高且准确)。

根据您工作的故事/功能/子系统,非程序员利益相关者可以向他们展示和理解这些规范的验证和反馈,尤其是敏捷和BDD的核心。

答案 4 :(得分:1)

我使用第二种方法,它确实有助于描述您的软件应该做什么。我还使用嵌套类来描述更详细的上下文。

本质上,测试类是上下文,可以嵌套,方法都是一行断言。例如,

public class MyClassSpecification
{
    protected MyClass instance = new MyClass();

    public class When_foobar_is_42 : MyClassSpecification 
    {
        public When_foobar_is_42() {
            this.instance.SetFoobar( 42 ); 
        }

        public class GetAnswer : When_foobar_is_42
        {
            private Int32 result;

            public GetAnswer() {
                this.result = this.GetAnswer();
            }

            public void should_return_42() {
                Assert.AreEqual( 42, result );
            }
        }
    }
}

将在我的测试运行器中提供以下输出:

MyClassSpecification+When_foobar_is_42+GetAnswer
    should_return_42

答案 5 :(得分:1)

我一直沿着你在问题中描述的两条道路以及其他一些道路走下去......你的第一个选择是非常直接的,对大多数人来说都很容易理解。我个人更喜欢BDD风格(你的第二个例子),因为它隔离了不同的上下文和对这些上下文的观察。唯一真正的缺点是它产生了更多的代码,所以开始这样做会感觉稍微麻烦,直到你看到整洁的测试。此外,如果您使用继承来重用夹具设置,您需要一个输出继承链的testrunner。考虑一个类“An_empty_stack”,你想重用它,然后再做另一个类:“When_five_is_pushed_on:An_empty_stack”你想要那个作为输出而不只是“When_five_is_pushed_on”。如果你的testrunner不支持这个,你的测试将包含多余的信息,如:“When_five_is_pushed_on_empty_stack:An_empty_stack”只是为了使输出更好。

答案 6 :(得分:0)

我投票支持调用测试用例类:EmployeeReaderTestCase并调用方法(),如http://xunitpatterns.com/Organization.htmlhttp://xunitpatterns.com/Organization.html#Test%20Naming%20Conventions