在一次采访中,有人问我“如何让代码难以进行单元测试?” 我最终喃喃自语地写了一些关于编写紧密耦合的代码的事情。谁能告诉我这个问题的正确答案/方法是什么?
5 回答
看看 Mishko 的指南:编写可测试的代码,在你的代码中引入尽可能多的这些缺陷,你最终会得到不可测试的代码。
例如:
- 在构造函数中做尽可能多的事情,启动线程,使用循环和 ifs
- 通过创建一长串方法调用来打破得墨忒耳法则
- 到处使用单例,从不要求依赖,在静态提供者中查找它们
- 用 2k 行代码创建上帝类
那么一些答案可能是
- 访问数据库的代码
- 根据系统日期时间运行的代码
- 在同一方法(单元)中执行多个功能的代码
- 具有大量附加行为的代码,它依赖于另一个不可读的代码
并且在一般情况下,任何难以/不可能模拟环境以使其表现出需要测试的方式的代码。
- 自己使用运算符创建类所需的依赖
new
项就足够了!这意味着紧密耦合的代码就是你的答案。 - 不遵循SOLID 原则的代码。
因此,在测试中,您将无法使用Mock
对象,因为您自己创建依赖项并对关系进行硬编码。
通过依赖注入,您可以使用多态行为,因此在构造函数或方法中传递给它的依赖项上调用某些方法的类不需要知道具体类型。所以在测试中你可以传递一个模拟对象,你就可以轻松地测试你的类。
Misko 的编写可测试代码解释了我们如何擅长编写不可测试的代码以及如何解决它。
示例(JAVA):
//hard to unit test this code as testing class A also requires that ClassB should work properly
//What is ClassB does some I/O or DB operations. This makes unit test a integration test
class classA{
ClassB b = new ClassB(); //Creating concrete dependencies
}
interface B{
//implemented by Class B and your mock class that you create for testing
}
class ClassA{
private B b;
//Here you can use mocking framework or create a mock class yourself and pass that as argument
//So the mock class will not do any DB or I/O and makes this unit test
public classA(B b){
this.b = b;
}
}
这是一个很好的答案。紧密耦合的代码极难进行单元测试(可能不应该进行单元测试——它应该首先重构),因为根据定义,单元测试只能测试某物的特定单元。单元测试应该避免对数据库或系统其他组件的所有调用,因为它们违反了这一点。
话虽如此,您还可以提到集成测试适用于测试更大的代码耦合或具有依赖关系的代码,甚至是基于行为的操作。您可以构建一个集成测试套件来测试您的 REST API,它具有许多依赖项,甚至跨多种技术和多种编程语言。
此外,如果不考虑设计或不使用体面的设计模式,可能会导致极度耦合或依赖的代码,如果不进行重构或重写,就很难或不可能进行单元测试。然后,您可以谈论 TDD(测试驱动开发http://en.wikipedia.org/wiki/Test-driven_development)或 BDD(行为驱动开发http://en.wikipedia.org/wiki/Behavior-driven_development)您首先要设计测试套件并从那里开始工作。
难以分离的代码 - 多个职责分布在多个类之间,但没有一个类完全承担任何责任
看起来非常复杂的代码 - 试试平均状态机的 500 行 if/then/else 炸弹。
在给定领域非常强大的代码,数学就是一个明显的例子。采用傅里叶变换函数并添加一个单元测试,显示全零转换为全零。100% 的覆盖率,但根本没有经过真正的测试。
与错综复杂的外部依赖关系强耦合的代码。
具有执行多种操作的巨大接口的代码。