4

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

[MethodName_StateUnderTest_ExpectedBehavior]

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

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

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

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

4

4 回答 4

5

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

SomeMethod_ExpectionalState_ThrowsInvalidOperationException
SomeMethod_ExceptionalState_ThrowsArgumentNullException

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

SomeMethod_DependencyReturnsCorrectResult_ReturnsResult
SomeMethod_WhenNothingSpecialHappens_ReturnsResult
SomeMethod_EverythingElseWorked_WorksToo

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

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

最后,不要盲目追随罗伊——把它当作指导方针,而不是惯例。约定很少适用于所有可能的情况,这次也不例外。

于 2012-08-09T10:15:39.317 回答
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 在两种情况下返回,这是现实 - 例外情况相同。

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

于 2012-08-09T09:46:55.510 回答
1

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

Failed unit tests:

MethodName_NegativeTestParams1_CorrectExceptionThrown

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

Failed unit tests:

MethodName_NegativeTestParams1

没有任何线索出了什么问题,直到您查看测试。

在这种情况下,为除了失败的单元测试列表之外没有上下文的情况进行规划,您应该使方法名称尽可能详细,CorrectExceptionThrown并根据需要重复多次。

此外,如果您对不同的测试有不同的例外,CorrectExceptionThrown则消息可能会变得不那么笼统:ArgumentExceptionThrown等等。

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

于 2012-08-09T10:05:12.140 回答
0

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

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

于 2012-08-09T09:12:40.030 回答