假设我有一些 A 类,它内部依赖于 B 类,它在私有(private)字段中初始化:
class SomeSpecialProcessing {
private BufferedWriter bufferedWriter;
// some other fields
public SomeSpecialProcessing() {
this.bufferedWriter = new BufferedWriter(new FileWriter("something.log"));
}
public String doSomeProcessing() {
// some special calculation
persistToDisc(somethingImportant);
// some special processing
return importantResult;
}
private void persistToDisc(String somethingImportant) {
// this.bufferedWriter.write(str);
}
}
现在我需要为公共(public)方法 doSomeProcessing() 创建单元测试,但我不想将任何内容写入光盘,因为这是一项耗时的操作。因此我必须模拟 bufferedWriter。
现在我有两种可能性:
- 允许类 SomeSpecialProcessing 使用 setter 或构造函数在外部设置 bufferedWriter,然后在单元测试中我会将模拟传递到该字段。
- 在单元测试中,我将使用反射模拟bufferedWriter。
现在我更喜欢使用反射,但很多人说这是不好的做法,并建议将bufferedWriter添加到构造函数或setter中。但我认为仅仅因为单元测试而暴露类的内部字段是愚蠢的。
如何解决此类问题?
最佳答案
But I think it's stupid to exposure internal fields of class just because of Unit tests
它不仅使您的代码更容易进行单元测试,而且总体上使您的代码更加灵活。
目前你的类(class)非常不灵活。它可以进行一些处理并保存到名为 something.log
的单个文件中。它以一种非常特定的方式(使用 BufferedWriter)写入它,这可能是也可能不是写入特定输出的最有效方式。基本上,您正在从类(class)用户手中夺取控制权。
通过将您的依赖项推广到任何可以在某处写入字符串的东西,您可以提高类的灵 active ,并允许其用户自己决定提供哪些最佳依赖项来满足他们的需求要求。
class SomeSpecialProcessing {
private Writer writer;
public SomeSpecialProcessing(Writer writer) {
this.writer = writer;
}
public String doSomeProcessing() {
// some special calculation
persist(somethingImportant);
// some special processing
return importantResult;
}
private void persist(String somethingImportant) {
this.writer.write(str);
}
}
您的类已经有 2 个用例:写入实际日志,而不执行任何操作。在某种程度上,您已经需要这种灵 active 。您想通过使用反射来回避这个问题,并声称它同样好。
问题是它并不那么好。基于反射的测试将变得更加脆弱。想重构私有(private)字段的名称吗?哦,看,我已经破坏了我的测试。想要更改内部实现以不使用 BufferedWriter 吗?哦,看,我已经破坏了我的测试。
关于java - 为什么 mock 私有(private)领域是不好的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50678127/