题
有谁知道在哪里可以找到单元测试指南和建议?我想要一些能够解决以下类型主题的内容(例如):
- 测试应该与应用程序逻辑在同一个项目中吗?
- 我应该有测试类来反映我的逻辑类,还是应该只拥有我认为需要的测试类?
- 我应该如何命名我的测试类、方法和项目(如果它们位于不同的项目中)
- 应该测试私有的、受保护的和内部的方法,还是只测试那些可公开访问的方法?
- 单元测试和集成测试应该分开吗?
- 有没有 好的 为什么没有 100% 的测试覆盖率?
我没有问什么是我应该问的?
在线资源将是最好的。
解决方案
我会推荐 肯特·贝克的 关于 TDD 的书。
另外,您还需要前往 马丁·福勒的 地点。他也有很多关于测试的好信息。
我们非常重视 TDD,所以我会从这个角度回答问题。
测试应该与应用程序逻辑在同一个项目中吗?
通常,我们将测试保留在同一个解决方案中,但我们将测试分解为单独的 DLL/项目,这些 DLL/项目反映了它们正在测试的 DLL/项目,但维护了命名空间,测试位于子命名空间中。例子:通用/通用测试
我应该有测试类来反映我的逻辑类,还是应该只拥有我认为需要的测试类?
是的,您的测试应该在创建任何类之前创建,并且根据定义,您应该只单独测试单个单元。因此,您的解决方案中的每个类都应该有一个测试类。
我应该如何命名我的测试类、方法和项目(如果它们位于不同的项目中)
我想强调的是,行为就是正在测试的内容,因此我通常以 SUT 命名测试类。例如,如果我有一个 User 类,我会像这样命名测试类:
public class UserBehavior
方法应该命名为描述您期望的行为。
public void ShouldBeAbleToSetUserFirstName()
项目可以按照您想要的方式命名,但通常您希望它正在测试的项目相当明显。请参阅之前有关项目组织的答案。
应该测试私有的、受保护的和内部的方法,还是只测试那些可公开访问的方法?
同样,您希望测试断言预期行为,就好像您是正在测试的对象的第三方消费者一样。如果您测试内部实现细节,那么您的测试将很脆弱。您希望您的测试能够让您自由地进行重构,而不必担心破坏现有功能。如果您的测试了解实现细节,那么如果这些细节发生变化,您将不得不更改您的测试。
单元测试和集成测试应该分开吗?
是的,单元测试需要与验收测试和集成测试分开。关注点分离也适用于测试。
有没有充分的理由不实现 100% 的测试覆盖率?
我不会纠结于 100% 代码覆盖率的事情。100% 的代码覆盖率往往意味着测试具有一定的质量水平,但这是一个神话。您可以进行糟糕的测试,但仍然获得 100% 的覆盖率。相反,我会依靠良好的“测试第一”心态。如果您总是在编写一行代码之前编写测试,那么您将确保 100% 的覆盖率,因此它成为一个有争议的问题。
一般来说,如果您专注于描述类的完整行为范围,那么您将无需担心。如果你将代码覆盖率作为一个指标,那么懒惰的程序员只会做足够多的事情来满足这个标准,而你的测试仍然很糟糕。相反,严重依赖同行评审,同时对测试进行评审。
其他提示
这是一个好问题。我们有机地发展自己的业务,我怀疑最好的方式就是这样。里面有一点“这取决于......”。
我们在同一个项目中的一个名为“UnitTes”的子命名空间中进行测试
我们的测试类镜像逻辑类,以便简化跟踪测试与测试内容的关系
类的命名类似于它们正在测试的逻辑类,方法的命名则取决于它们正在测试的场景。
我们只为公共方法和内部方法编写测试(测试在同一个项目中),目标是类的 95% 覆盖率。
我不想区分“单元”和“整合”。我们将花费大量时间试图弄清楚哪个是哪个……包那个!测试就是测试。
始终达到 100% 太困难了。我们的目标是95%。获得最后 5% 所需的时间以及实际捕获的内容也会带来收益递减。
这就是我们,以及适合环境和节奏的东西。您的里程可能会有所不同。想想你的环境和所涉及的人物。
我期待看到其他人对此有何评论!
乔什的回答是正确的 - 只需澄清一点:
我将单元测试与集成和验收测试分开的原因是速度。我使用TDD。我需要关于我刚刚创建/修改的代码行的即时反馈。如果我正在运行全套集成和/或验收测试(涉及真实磁盘、真实网络以及非常慢且不可预测的外部系统的测试),我就无法得到这一点。
不要越过横梁。如果你这样做,就会发生不好的事情。
我强烈推荐你阅读 测试驱动开发:举例说明 和 测试驱动开发:实用指南 单个主题的问题太多
关于你的最后一个问题,根据我的经验,不坚持 100% 测试覆盖率的“好”理由是,要获得最后几个百分点需要付出不成比例的努力,特别是在较大的代码库中。因此,一旦达到收益递减点,就需要决定是否值得花时间。
为了:
- 不,通常最好将它们包含在一个单独的项目中;除非您希望能够在运行时运行诊断。
- 理想的情况是 100% 代码覆盖率,这意味着每个类的每个例程中的每一行代码。
- 我选择 ClassnameTest, ClassnameTest.MethodNameTestnumber
- 一切。
- 我会说是的,因为如果单元测试失败,则不需要运行集成测试。
- 仅设置和获取字段的简单属性不需要测试。
测试应该与应用程序逻辑在同一个项目中吗?
这取决于。无论哪种方式都需要权衡。
将其保留在一个项目中需要额外的带宽来分发项目、额外的构建时间并增加安装占用空间,并且更容易犯下依赖于测试代码的生产逻辑的错误。
另一方面,保留单独的项目可能会使编写涉及私有方法/类(取决于编程语言)的测试变得更加困难,并且会导致一些小的管理麻烦,例如建立一个新的开发环境(例如当新的开发人员加入该项目时)会更加困难。
这些不同成本的影响程度因项目而异,因此没有通用的答案。
我应该有测试类来反映我的逻辑类,还是应该只拥有我认为需要的测试类?
不。
您应该拥有允许精心设计的测试代码的测试类(即最少的重复、明确的意图等)。
直接镜像测试类中的逻辑类的明显优点是可以轻松找到与特定代码段相对应的测试。还有其他方法可以解决这个问题而不限制测试代码的灵活性。测试模块和类的简单命名约定通常就足够了。
我应该如何命名我的测试类、方法和项目(如果它们位于不同的项目中)
您应该这样命名它们:
- 每个测试类和测试方法都有明确的目的,并且
- 以便寻找特定测试(或有关特定单元的测试)的人可以轻松找到它。
应该测试私有的、受保护的和内部的方法,还是只测试那些可公开访问的方法?
通常应该测试非公开方法。这取决于您是否通过测试公共接口获得足够的信心,或者您真正想要测试的单元是否不可公开访问。
单元测试和集成测试应该分开吗?
这取决于您选择的测试框架。采取最适合您的测试框架的方式,并使其:
- 与一段代码相关的单元测试和集成测试都很容易找到,
- 仅运行单元测试很容易,
- 仅运行集成测试很容易,
- 运行所有测试都很容易。
有没有充分的理由不实现 100% 的测试覆盖率?
是的,这是有充分理由的。严格来说,“100% 测试覆盖率”意味着代码中的每种可能情况都经过测试。这对于几乎任何项目来说都是不切实际的。
如果你简单地认为“100% 测试覆盖率”意味着每一行源代码都在某个时刻被测试套件执行,那么这是一个很好的目标,但有时只有几行在尴尬的地方很难达到自动化测试的目的。如果定期手动验证该功能的成本低于通过扭曲到达最后五行的成本,那么这就是不实现 100% 行覆盖的充分理由。
鼓励您的开发人员发现,而不是应该拥有 100% 线路覆盖率的简单规则 任何 测试中的差距,并找到解决这些差距的方法,无论“覆盖”的行数是否有所改善。换句话说,如果您测量线路覆盖范围,那么您将提高线路覆盖范围,但您真正想要的是提高质量。因此,不要忘记线路覆盖率只是质量的一个非常粗略的近似值。