命名单元测试类和测试方法的最佳实践是什么?
之前在SO上讨论了这个问题,单元测试有哪些流行的命名约定?
我不知道这是一个非常好的方法,但是目前在我的测试项目中,我在每个生产类和测试类之间都有一对一的映射,例如Product
和ProductTest
.
在我的测试类中,然后我有方法,其中包含我正在测试的方法的名称,下划线,然后是情况和我期望发生的事情,例如Save_ShouldThrowExceptionWithNullName()
.
我喜欢Roy Osherove的命名策略,它是以下内容:
[UnitOfWork_StateUnderTest_ExpectedBehavior]
它具有方法名称和结构化方式所需的所有信息.
工作单元可以是单个方法,类,也可以是多个类.它应代表在此测试用例中要测试的所有内容并受到控制.
对于程序集,我使用典型的.Tests
结尾,我认为它非常普遍,对于类(结束于Tests
)是相同的:
[NameOfTheClassUnderTestTests]
以前我使用Fixture作为后缀而不是测试,但我认为后者更常见,然后我更改了命名策略.
我喜欢跟着"应该"命名标准测试而命名的测试夹具被测单元后(即类).
为了说明(使用C#和NUnit):
[TestFixture]
public class BankAccountTests
{
[Test]
public void Should_Increase_Balance_When_Deposit_Is_Made()
{
var bankAccount = new BankAccount();
bankAccount.Deposit(100);
Assert.That(bankAccount.Balance, Is.EqualTo(100));
}
}
为什么"应该"?
我发现它迫使测试编写者用一句话来命名测试,这句话应该是"应该[在某种状态] [之后/之前/之后] [动作发生]"
是的,写"应该"到处都会有点重复,但正如我所说,它迫使作者以正确的方式思考(这对初学者也有好处).另外,它通常会产生可读的英语测试名称.
更新:
我注意到Jimmy Bogard也是'should'的粉丝,甚至还有一个名为Should的单元测试库.
更新(4年后......)
对于那些感兴趣的人,我的命名测试方法已经发展了多年.一个与该问题是否应模式我上面描述的作为其不容易知道一目了然地看出哪些方法是测试.对于OOP,我认为使用测试方法启动测试名称更有意义.对于设计良好的类,这应该导致可读的测试方法名称.我现在使用类似的格式
.显然,根据上下文,您可能希望将"应该/何时"动词替换为更合适的内容.例:
Deposit_ShouldIncreaseBalance_WhenGivenPositiveValue()
我喜欢这种命名方式:
OrdersShouldBeCreated(); OrdersWithNoProductsShouldFail();
等等.对于非测试者来说,问题是什么是非常明确的.
Kent Beck建议:
每个'单元'一个测试夹具(程序类).测试装置本身就是课程.测试夹具名称应为:
[name of your 'unit']Tests
测试用例(测试夹具方法)的名称如下:
test[feature being tested]
例如,具有以下类:
class Person { int calculateAge() { ... } // other methods and properties }
测试夹具将是:
class PersonTests { testAgeCalculationWithNoBirthDate() { ... } // or testCalculateAge() { ... } }
班级名称.对于测试夹具名称,我发现"测试"在许多领域的普遍存在的语言中非常普遍.例如,在工程领域:StressTest
和化妆品领域:SkinTest
.很抱歉不同意肯特,但在我的测试装置(StressTestTest
?)中使用"测试" 令人困惑.
"单位"在域名中也被大量使用.例如MeasurementUnit
.是一个称为MeasurementUnitTest
"测量"或"MeasurementUnit"的测试类吗?
因此,我喜欢为我的所有测试类使用"Qa"前缀.例如QaSkinTest
和QaMeasurementUnit
.它永远不会与域对象混淆,并且使用前缀而不是后缀意味着所有测试夹具在视觉上共存(如果您的测试项目中有假货或其他支持类,则非常有用)
命名空间.我在C#中工作,并且我将测试类保持在与他们正在测试的类相同的命名空间中.它比拥有单独的测试命名空间更方便.当然,测试类是在不同的项目中.
测试方法名称.我喜欢命名我的方法WhenXXX_ExpectYYY.它使前提条件清晰,并有助于自动化文档(la TestDox).这类似于Google测试博客上的建议,但更多地分离了前提条件和期望.例如:
WhenDivisorIsNonZero_ExpectDivisionResult WhenDivisorIsZero_ExpectError WhenInventoryIsBelowOrderQty_ExpectBackOrder WhenInventoryIsAboveOrderQty_ExpectReducedInventory
我使用Given-When-Then概念.看看这篇短文http://cakebaker.42dh.com/2009/05/28/given-when-then/.文章根据BDD描述了这个概念,但您也可以在TDD中使用它而不做任何更改.
请参阅:http: //googletesting.blogspot.com/2007/02/tott-naming-unit-tests-responsibly.html
对于测试方法名称,我个人觉得使用详细和自我记录的名称非常有用(与Javadoc注释一起进一步解释测试正在做什么).
我最近提出了以下约定,用于命名我的测试,它们的类和包含项目,以便最大化它们的描述:
假设我正在测试MyApp.Serialization命名空间中项目中的Settings类.
首先,我将使用MyApp.Serialization.Tests命名空间创建一个测试项目.
在这个项目中,当然命名空间我将创建一个名为IfSettings的类(保存为IfSettings.cs).
让我们说我正在测试SaveStrings()方法.- >我将测试命名为CanSaveStrings().
当我运行此测试时,它将显示以下标题:
MyApp.Serialization.Tests.IfSettings.CanSaveStrings
我认为这很好地告诉了我,它正在测试什么.
当然,在英语中,名词"Tests"与动词"tests"相同是有用的.
在命名测试时,您的创造力没有限制,因此我们可以为他们获得完整的句子标题.
通常,测试名必须以动词开头.
例子包括:
检测(例如DetectsInvalidUserInput)
投掷(例如ThrowsOnNotFound)
威尔(例如WillCloseTheDatabaseAfterTheTransaction)
等等
另一种选择是使用"that"而不是"if".
后者节省了我,虽然按键和描述更准确地说我在做什么,因为我不知道,那测试的行为是存在的,但正在测试,如果它是.
[ 编辑 ]
在使用上述命名约定后,我发现,在使用接口时,If前缀可能会令人困惑.碰巧的是,测试类IfSerializer.cs看起来非常类似于"打开文件选项卡"中的接口ISerializer.cs.当在测试,被测试的类及其接口之间来回切换时,这会非常烦人.结果我现在会选择这在如果作为前缀.
另外我现在使用 - 仅用于我的测试类中的方法,因为它在其他任何地方都不被认为是最佳实践 - "_"用于分隔我的测试方法名称中的单词,如:
[测试] public void detected_invalid_User_Input()*
我发现这更容易阅读.
[ 结束编辑 ]
我希望这会产生更多的想法,因为我认为命名测试非常重要,因为它可以为您节省大量时间,否则将花费大量时间来试图了解测试正在做什么(例如,在延长的中断后恢复项目) .
我认为最重要的事情之一是在您的命名约定中保持一致(并与您团队中的其他成员达成一致).很多时候,我在同一个项目中看到了大量不同的约定.