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


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

  • Reading_Valid_Employee_Data_Correctly_Generates_Employee_Object
  • Reading_Missing_Employee_Data_Throws_Invalid_Employee_ID_Exception

等等。

我最近一直在读一篇关于 不同类型的命名约定 用于BDD。我喜欢这个命名的可读性,最终得到一个类似的测试列表:

  • When_Reading_Valid_Employee(夹具)
    • Employee_Object_Is_Generated(方法)
    • Employee_Has_Correct_ID(方法)
  • When_Reading_Missing_Employee(夹具)
    • An_Invalid_Employee_ID_Exception_Is_Thrown(方法)

等等。

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


5426
2018-06-19 15:13


起源



答案:


您的第二个示例(每个逻辑“任务”都有一个夹具,而不是每个类的一个)具有以下优点:您可以为每个任务使用不同的SetUp和TearDown逻辑,从而简化您的各个测试方法并使其更具可读性。

你不需要在一个或另一个作为标准。我们使用两者的混合,取决于我们必须为每个类测试多少个不同的“任务”。


3
2018-06-19 15:17





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

functionName_shouldDoThis_whenThisIsTheSituation

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

pop_shouldThrowEmptyStackException_whenTheStackIsEmpty

pop_shouldReturnTheObjectOnTheTopOfTheStack_whenThereIsAnObjectOnTheStack


6
2018-06-19 15:29





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


2
2018-06-19 15:23





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

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

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


1
2017-07-03 04:28





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

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

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

1
2017-07-27 01:03





我一直沿着你在问题中描述的两条道路以及其他一些道路......你的第一个选择是非常直接的,对大多数人来说都很容易理解。我个人更喜欢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”只是为了使输出更好。


1
2017-08-21 05:11





我投票调用测试用例类:EmployeeReaderTestCase并调用方法()之类的 http://xunitpatterns.com/Organization.html 和 http://xunitpatterns.com/Organization.html#Test%20Naming%20Conventions


0
2017-07-03 04:47