11

我目前对我的单元测试使用一个简单的约定。如果我有一个名为“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(方法)

等等。

有人用过这两种命名方式吗?你能提供任何建议、好处、缺点、陷阱等来帮助我决定是否为我的下一个项目切换吗?

4

7 回答 7

8

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

functionName_shouldDoThis_whenThisIsTheSituation

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

pop_shouldThrowEmptyStackException_whenTheStackIsEmpty

pop_shouldReturnTheObjectOnTheTopOfTheStack_whenThereIsAnObjectOnTheStack

于 2009-06-19T15:29:34.093 回答
3

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

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

于 2009-06-19T15:17:29.733 回答
2

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

于 2009-06-19T15:23:33.293 回答
1

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

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

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

于 2009-07-03T04:28:13.677 回答
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
于 2009-07-27T01:03:06.840 回答
1

我一直在您在问题中描述的两条道路以及其他一些道路上……您的第一个选择对大多数人来说非常简单且易于理解。我个人更喜欢 BDD 样式(您的第二个示例),因为它隔离了不同的上下文并将对这些上下文的观察分组。唯一真正的缺点是它会生成更多代码,因此在您看到整洁的测试之前,开始这样做会感觉有点麻烦。此外,如果您使用继承来重用夹具设置,您需要一个输出继承链的测试运行程序。考虑一个类“An_empty_stack”,并且您想重用它,然后您再做另一个类:“When_five_is_pushed_on:An_empty_stack”您希望将其作为输出,而不仅仅是“When_five_is_pushed_on”。

于 2009-08-21T05:11:24.347 回答
0

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

于 2009-07-03T04:47:04.957 回答