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

发布于 2024-07-25 13:54:03 字数 796 浏览 3 评论 0原文

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

等等。

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

I currently use a simple convention for my unit tests. If I have a class named "EmployeeReader", I create a test class named "EmployeeReader.Tests. I then create all the tests for the class in the test class with names such as:

  • Reading_Valid_Employee_Data_Correctly_Generates_Employee_Object
  • Reading_Missing_Employee_Data_Throws_Invalid_Employee_ID_Exception

and so on.

I have recently been reading about a different type of naming convention used in BDD. I like the readability of this naming, to end up with a list of tests something like:

  • When_Reading_Valid_Employee (fixture)
    • Employee_Object_Is_Generated (method)
    • Employee_Has_Correct_ID (method)
  • When_Reading_Missing_Employee (fixture)
    • An_Invalid_Employee_ID_Exception_Is_Thrown (method)

and so on.

Has anybody used both styles of naming? Can you provide any advice, benefits, drawbacks, gotchas, etc. to help me decide whether to switch or not for my next project?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

南风几经秋 2024-08-01 13:54:03

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

functionName_shouldDoThis_whenThisIsTheSituation

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

pop_shouldThrowEmptyStackException_whenTheStackIsEmpty

pop_shouldReturnTheObjectOnTheTopOfTheStack_whenThereIsAnObjectOnTheStack

The naming convention I've been using is:

functionName_shouldDoThis_whenThisIsTheSituation

For example, these would be some test names for a stack's 'pop' function

pop_shouldThrowEmptyStackException_whenTheStackIsEmpty

pop_shouldReturnTheObjectOnTheTopOfTheStack_whenThereIsAnObjectOnTheStack

把时间冻结 2024-08-01 13:54:03

您的第二个示例(为每个逻辑“任务”提供一个固定装置,而不是为每个类提供一个固定装置)的优点是您可以为每个任务使用不同的 SetUp 和 TearDown 逻辑,从而简化您的单独测试方法并使它们更具可读性。

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

Your second example (having a fixture for each logical "task", rather than one for each class) has the advantage that you can have different SetUp and TearDown logic for each task, thus simplifying your individual test methods and making them more readable.

You don't need to settle on one or the other as a standard. We use a mixture of both, depending on how many different "tasks" we have to test for each class.

且行且努力 2024-08-01 13:54:03

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

I feel the second is better because it makes your unit tests more readable to others as long lines make the code look more difficult to read or make it more difficult to skim through. If you still feel there's any ambiguity as for what the test does, you can add comments to clarify this.

乖不如嘢 2024-08-01 13:54:03

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

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

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

Part of the reasoning behind the 2nd naming convention that you reference is that you are creating tests and behavioural specifications at the same time. You establish the context in which things are happening and what should actually then happen within that context. (In my experience, the observations/test-methods often start with "should_," so you get a standard "When_the_invoicing_system_is_told_to_email_the_client," "should_initiate_connection_to_mail_server" format.)

There are tools that will reflect over your test fixtures and output a nicely formatted html spec sheet, stripping out the underscores. You end up with human-readable documentation that is in sync with the actual code (as long as you keep your test coverage high and accurate).

Depending on the story/feature/subsystem on which you're working, these specifications can be shown to and understood by non-programmer stakeholders for verification and feedback, which is at the heart of agile and BDD in particular.

弃爱 2024-08-01 13:54:03

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

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

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

I use second method, and it really helps with describing what your software should do. I also use nested classes to describe more detailed context.

In essence, test classes are contexts, which can be nested, and methods are all one line assertions. For example,

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 );
            }
        }
    }
}

which will give me following output in my test runner:

MyClassSpecification+When_foobar_is_42+GetAnswer
    should_return_42
若水般的淡然安静女子 2024-08-01 13:54:03

我一直沿着您在问题中描述的两条路以及其他一些路走...您的第一个选择对于大多数人来说非常直接且易于理解。 我个人更喜欢 BDD 风格(你的第二个例子),因为它隔离了不同的上下文,并对这些上下文的观察进行分组。 唯一真正的缺点是它会生成更多代码,因此在您看到简洁的测试之前,开始执行会感觉稍微麻烦一些。 此外,如果您使用继承来重用夹具设置,您需要一个输出继承链的测试运行器。 考虑一个类“An_empty_stack”,并且您想重用它,因此您可以执行另一个类:“When_ Five_is_pushed_on : An_empty_stack”,您希望将其作为输出,而不仅仅是“When_ Five_is_pushed_on”。 如果您的测试运行程序不支持这一点,您的测试将包含冗余信息,例如:“When_ Five_is_pushed_on_empty_stack:An_empty_stack”只是为了使输出更好。

I've been down the two roads you describe in your question as well as a few other... Your first alternative is pretty straight forward and easy to understand for most people. I personally like the BDD style (your second example) more because it isolates different contexts and groups observations on those contexts. Th only real downside is that it generates more code so starting to do it feels slightly more cumbersome until you see the neat tests. Also if you use inheritance to reuse fixture setup you want a testrunner that outputs the inheritance chain. Consider a class "An_empty_stack" and you want to reuse it so you then do another class: "When_five_is_pushed_on : An_empty_stack" you want that as output and not just "When_five_is_pushed_on". If your testrunner does not support this your tests will contain redundant information like: "When_five_is_pushed_on_empty_stack : An_empty_stack" just to make the output nice.

烏雲後面有陽光 2024-08-01 13:54:03

我投票赞成调用测试用例类:EmployeeReaderTestCase并调用methods(),例如 http://xunitpatterns.com/Organization .htmlhttp://xunitpatterns.com/Organization.html#Test %20命名%20约定

i vote for calling the test case class: EmployeeReaderTestCase and calling the methods() like http://xunitpatterns.com/Organization.html and http://xunitpatterns.com/Organization.html#Test%20Naming%20Conventions

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文