单元测试规范

单元测试规范 #

名词解释 #

覆盖率 #

覆盖率是对自动化测试运行期间执行了多少代码产生的度量(100%覆盖意味着每一行代码都至少执行过) 不必追求100%的覆盖率,覆盖率在60%-80%是一个不错的范围,这个主要根据项目的情况来决定。

单元测试原则 #

DAMP 和DRY 这是一种平衡,而不是矛盾
DAMP 和 DRY 并不矛盾,而是平衡了代码可维护性的两个不同方面。可维护的代码(易于更改的代码)是这里的最终目标。
DAMP(描述性和有意义的短语)提高了代码的可读性。
要维护代码,首先需要了解代码。要理解它,你必须阅读它。考虑一下你花多少时间阅读代码。这是很多。 DAMP 通过减少阅读和理解代码所需的时间来提高可维护性。
DRY(不要重复自己)促进代码的 正交性
删除重复确保系统中的每个概念在代码中都有一个单一的权威表示。对单个业务概念的更改会导致对代码的一次更改。DRY 通过将更改(风险)隔离到系统中必须更改的那些部分来提高可维护性。
那么,为什么重复在测试中更容易接受?
测试通常包含固有的重复,因为它们一遍又一遍地测试相同的东西,只是输入值或设置代码略有不同。但是,与生产代码不同的是,这种重复通常仅与单个测试夹具/文件中的场景隔离。因此,重复是最小的和明显的,这意味着它比其他类型的重复给项目带来的风险更小。
此外,删除这种重复会降低测试的可读性。以前在每个测试中重复的细节现在隐藏在一些新方法或类中。为了全面了解测试,您现在必须在精神上将所有这些部分重新组合在一起。
因此,由于测试代码重复通常带来的风险较小,并提高了可读性,因此很容易看出它是如何被认为是可以接受的。
原则上,在生产代码中使用 DRY,在测试代码中使用 DAMP。虽然两者同等重要,但只要稍加智慧,您就可以在对自己有利的情况下平衡。
引用自: 在谈论单元测试时,“DAMP not DRY"是什么意思?

单元测试的准则 #

  • 单元测试应该是可靠的,否则不能保证测试结果可信;
  • 单元测试应该是可维护且易于阅读和理解的;
  • 单元测试的每一个测试单元只测试一个用例,这样便于维护;
  • 单元测试应该可以在任何机器上顺序运行,且不会相互影响,如果可以,希望也能不依赖环境因素或全局/外部状态;
  • 单元测试应该自动化;
  • 结合使用单元测试和集成测试;
  • 单元测试应在有组织的测试实践中执行;

单元测试用例的命名方法 #

这里提供以下七种命名方法以供参考

MethodName_StateUnderTest_ExpectedBehavior(方法名_在测试状态_预期行为) #

如果方法名在重构的时候被更改,那么测试用例也应该同样被更改,否则以后会难以被理解。示例:
isAdult_AgeLessThan18_False
withdrawMoney_InvalidAccount_ExceptionThrown
admitStudent_MissingMandatoryFields_FailToAdmit

MethodName_ExpectedBehavior_StateUnderTest(方法名_预期行为_在测试状态) #

与第一种有相同的问题。示例:
isAdult_False_AgeLessThan18
withdrawMoney_ThrowsException_IfAccountIsInvalid
admitStudent_FailToAdmit_IfMandatoryFieldsAreMissing

test[Feature being tested](test要测试的功能) #

将要测试的功能作为测试名称,增加了可读性。示例:
testIsNotAnAdultIfAgeLessThan18
testFailToWithdrawMoneyIfAccountIsInvalid
testStudentIsNotAdmittedIfMandatoryFieldsAreMissing
也可以选择去掉前缀test。示例:
IsNotAnAdultIfAgeLessThan18
FailToWithdrawMoneyIfAccountIsInvalid
StudentIsNotAdmittedIfMandatoryFieldsAreMissing

Should_ExpectedBehavior_When_StateUnderTest(Should_预期行为_When_在测试状态) #

Should_ThrowException_When_AgeLessThan18
Should_FailToWithdrawMoney_ForInvalidAccount
Should_FailToAdmit_IfMandatoryFieldsAreMissing

When_StateUnderTest_Expect_ExpectedBehavior(When_在测试状态_Expect_预期行为) #

When_AgeLessThan18_Expect_isAdultAsFalse
When_InvalidAccount_Expect_WithdrawMoneyToFail
When_MandatoryFieldsAreMissing_Expect_StudentAdmissionToFail

Given_Preconditions_When_StateUnderTest_Then_ExpectedBehavior(Given_先决条件_When_在测试状态_Expect_预期行为) #

此方法基于作为行为驱动开发(BDD)一部分开发的命名约定。想法是将测试分为三部分,以便可以提出先决条件,测试状态和预期行为,并以上述格式编写。示例:
Given_UserIsAuthenticated_When_InvalidAccountNumberIsUsedToWithdrawMoney_Then_TransactionsWillFail

参考资料 #

在马桶上测试:测试过干吗?让他们成为DAMP!
单元测试最佳实践:如何最大程度地利用测试自动化
7种流行的单元测试命名约定
TDD–测试驱动开发入门
单元测试的命名标准