【问题标题】:Osherove's naming convention for negative unit tests?Osherove 的负单元测试命名约定?
【发布时间】:2012-08-06 11:29:36
【问题描述】:

我正在尝试确定单元测试的命名约定。我喜欢 Roy Osherove 推荐的那一款:

[MethodName_StateUnderTest_ExpectedBehavior]

http://osherove.com/blog/2005/4/3/naming-standards-for-unit-tests.html

对于我们正在测试应用程序是否通过抛出异常正确处理错误行为的负面测试,我不确定这个标准。

因此,在这种情况下,ExpectedBehavior 将始终为“CorrectExceptionThrown”。为每个负面单元测试编写 ExpectedBehavior 是否仍然有意义,或者是否可以将其设为可选?

有利有弊。一方面,否定测试总是相同的,因此每次都编写它是多余的,它使单元测试方法名称变长。如果我们将其设为可选,则在必要时不会为单元测试添加预期行为也是一种风险。我还认为最好在整个项目中保持一致,以便在任何地方都以相同的方式应用它。

【问题讨论】:

  • 我不确定它是否可以仅仅因为它是重复的而被称为“冗余”。它说明了每种情况下的测试。

标签: c# unit-testing refactoring naming-conventions


【解决方案1】:

指定抛出什么异常作为操作结果没有什么多余的。这实际上完全符合 Roy 的命名约定,因为:

SomeMethod_ExpectionalState_ThrowsInvalidOperationException
SomeMethod_ExceptionalState_ThrowsArgumentNullException

您将获得有关您的代码的重要信息 - 引发的异常类型。但是,当您进行经典快乐路径测试时,名称某些部分的有用性是主观的。考虑:

SomeMethod_DependencyReturnsCorrectResult_ReturnsResult
SomeMethod_WhenNothingSpecialHappens_ReturnsResult
SomeMethod_EverythingElseWorked_WorksToo

这些名字携带什么信息?比较少。 ReturnsResult 本质上意味着它有效。 NothingSpecialHappens 也是相当模糊的信息。在这种情况下,删除部分名称可能是合理的。

但请注意,可能值得考虑更改名称,而不是完全删除其中的一部分(例如,ReturnsResult 可以替换为不那么模糊的ReturnsEntityFromDatabaseReturnsSerializedValue)。

最后,不要盲目跟随 Roy - 将其视为指南,而不是惯例。约定很少适用于所有可能的情况,这次也不例外。

【讨论】:

    【解决方案2】:

    你可以写:

    [Test]
    public void Foo_ExceptionalCaseX1_ExceptionY1Thrown()
    {
    }
    
    [Test]
    public void Foo_ExceptionalCaseX2_ExceptionY2Thrown()
    {
    }
    
    ...
    

    如果异常情况不同,抛出的异常类型相同,则没有冗余(即使后缀相同)。
    和写这两个测试没什么区别:

    [Test]
    public void Foo_SomeCaseX1_42Returned()
    {
    }
    
    [Test]
    public void Foo_SomeCaseX2_42Returned()
    {
    }
    
    ...
    

    你能做什么 - 42 在两种情况下返回,这就是现实 - 例外情况也是如此。

    还有一件事:当人们阅读一系列测试时,它们可能看起来(几乎)相同,但是当其中一个有一天失败时,幸运的开发人员将能够立即知道预期的行为是什么.每个测试都应该代表自己。

    【讨论】:

      【解决方案3】:

      想象一下单个单元测试失败的情况。然后你会从 CI 收到这样的消息:

      Failed unit tests:
      
      MethodName_NegativeTestParams1_CorrectExceptionThrown
      

      没有其他上下文。你看到问题(抛出了不正确的异常)。如果您将此设置为可选或尝试缩短您的方法名称,您最终可能会得到

      Failed unit tests:
      
      MethodName_NegativeTestParams1
      

      没有任何线索,直到您查看测试。

      在这种情况下,当你除了失败的单元测试列表之外没有上下文的情况下,你应该使方法名称尽可能详细,根据需要重复CorrectExceptionThrown

      此外,CorrectExceptionThrown 消息可能不那么笼统:ArgumentExceptionThrown 等,以防您对不同的测试有不同的例外情况。

      因此,我会在所有情况下都包含预期的行为,尽管有时它可能看起来是不必要的重复。

      【讨论】:

        【解决方案4】:

        我认为这是真的;但是,这只是决定单元测试命名约定的一种方式。如果您显然知道此测试中的异常抛出,我认为 .NET 框架单元测试将提供一种类似于 JUnit 的简单方法。

        @Test (IOException.class) public void testIOException() {...}

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2010-09-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-12-14
          • 2016-05-24
          相关资源
          最近更新 更多