对于我上一个Java项目,我对所有类进行了单元测试。每个类都有自己的接口和实现(即Person和PersonImpl)。类只通过接口相互交互,我使用模拟测试每个类独立于其他类。它最终真的很痛苦,因为它打破了我的日食ctrl +点击导航,因为在界面上调用每个方法调用。每次我创建一个对象时,它还需要创建和传递依赖工厂,这也会使业务代码变得混乱,当对象创建它的依赖项时,它完全没有问题(除了测试之外)。我偶然发现了另一种形式的依赖注入似乎可以解决这两个问题,我想知道是否有人能告诉我为什么这不是一个好主意。
这是一个简单,人为的非现实的例子......假设File和FileFactory是接口。
基于接口的构造函数DI
public class Logger {
private File file;
public Logger(FileFactory fileFactory, String fileName) {
file = fileFactory.create(fileName);
file.createNewFile();
}
public void debug(String message) {
file.append("[debug] " + message);
}
public void error(String message) {
file.append("[error] " + message);
}
}
部分模拟依赖注入
public class Logger {
private File file;
public Logger(String fileName) {
file = createFile(fileName);
file.createNewFile();
}
public void debug(String message) {
file.append("[debug] " + message);
}
public void error(String message) {
file.append("[error] " + message);
}
public File createFile(String fileName) {
return new File(fileName);
}
}
使用第二个示例,没有接口或工厂,并且类之间的关系被保留,因此我可以按住Ctrl并单击“createNewFile()”或“append”。在编写测试时,我可以对Mockito这个类进行部分模拟,并指示它返回一个模拟文件“createFile(String)”,所以我仍然可以在测试期间注入依赖项。我认为这样做有好处。我没有看到任何缺点吗?
答案 0 :(得分:1)
我不太喜欢java,但我知道C#中的DI,所以我想我可以帮助一下。
首先,请阅读此stackoverflow question。我已经问过要测试什么以及为什么要进行模拟。希望这个问题可以提供进行单元测试的一般概念。
对我来说,在模拟对象中应该做些什么:
简单
简单的模拟对象可以让您的测试单元更容易查看。简单的模拟对象可以使它变得微不足道,并且不需要对模拟对象进行任何测试。一个简单的模拟对象将支持下面的第4点。
具有最小依赖性
在您的情况下,您对FileFactory的依赖性较低。这很好,因为它更容易设置测试。拥有最小依赖性的另一个好处是它具有最小的测试范围。它也将支持下面的第4点。
没有该界面的附加功能
在您的示例中,您有另一个函数public File createFile
。我想知道它是否会被消费者使用(它是公开的)。恕我直言,最好将其设为私有,以确保单元测试不会调用其他方法。
更改测试类时不会破坏测试类
模拟对象最重要的一点是当更改测试类(使用者)时,模拟对象不会导致错误。因为您要对测试类进行单元测试,所以任何错误都只应由测试类引起。更难跟踪模拟对象引起错误的时间。