如何使用 Mockito 模拟方法的局部变量/变量方法



我有一个名为A的类和方法method1()

Class A{
boolean method1(String path){
File procDir = new File(path);
if(!procDir.exists()){
return false`;
}
if(!procDir.canRead()){
return false;
}
}
}

考虑上面的代码,有人会建议,破解方法1和内部方法/变量(procDir.canRead())的方法。

第一个答案是:你不能单独使用Mockito。

你需要一个能够模拟对new调用的模拟框架。例如PowerMock(ito)或JMockit。您可以在此处找到有关如何使用 PowerMock 执行此操作的文档。从这个意义上说,从技术上讲,这是一个已解决的问题 - 它只需要一些摆动就可以让它工作(如果你弄错了一个先决条件,它根本不起作用)。

但除此之外,其他答案都是正确的:你创建了难以测试的代码,现在你正在寻找一个创可贴来解决你不灵活的设计的后果。

因此,与其花费宝贵的时间在 PowerMock(ito) 上,不如遵循您已经得到的建议并修复测试问题的根本原因。例如,通过使用某种依赖关系注入向此代码提供 File 对象(而不是让此代码调用new本身)。

这是一个设计问题,因为该方法与File紧密耦合

显式依赖关系原则指出:

方法和类应显式要求(通常通过方法参数或构造函数参数)它们需要的任何协作对象才能正常运行。

考虑到这一点,请考虑重构方法以显式依赖于File

boolean method1(File procDir){    
if(!procDir.exists()){
return false`;
}
if(!procDir.canRead()){
return false;
}
return true;
}

这也会将依赖项的创建反转为类/方法外部的委托。这也允许方法显式声明它实际需要的内容。

现在该方法已解耦,可以通过传递正确的文件或模拟来测试该方法。

您还可以考虑抽象File

public interface FileInfo {
boolean exists();
boolean canRead()
}

因为类应该依赖于抽象而不是具体化。

boolean method1(FileInfo procDir){    
if(!procDir.exists()){
return false`;
}
if(!procDir.canRead()){
return false;
}
return true;
}

然后,FileInfo的实现可以封装实际File并公开所需的行为。

对于测试,现在应该更容易通过继承或模拟框架直接模拟/存根/伪造抽象。

FileInfo file = mock(FileInfo.class);
when(file.exists()).thenReturn(true);
when(file.exists()).thenReturn(true);
subject.method1(file);

您可以使用 JUnit 的 TemporaryFolder 规则(或者,如果使用 JUnit5,则使用其等效扩展名)为您的测试创建输入文件。

然后你会...

  • 将此文件的路径传递到method1()- 测试快乐路径
  • 将不存在的文件路径传递到method1()以测试!procDir.exists()悲伤路径

测试完成后,JUnit将丢弃临时文件夹,从而坚持自包含的测试原则。

此方法允许您在没有任何模拟的情况下测试代码,同时仍然是自包含的单元测试。

或者,您可以将File procDir = new File(path);调用隐藏在接口后面:

public interface FileCreator {
File create(String path);
}

通过一个简单的实现:

public class FileCreatorImpl implements FileCreator {
public File create(String path) {
return new File(path);    
}
}

测试时,可以将Mock(FileCreator.class)注入到包含method1()的类的实例中,并按如下方式设置对该实例的期望:

String filePath = "...";
File file = Mockito.mock(File.class);
Mockito.when(fileCreator.create(filePath)).thenReturn(file);
// happy path
Mockito.when(file.exists()).thenReturn(true);
Mockito.when(file.canRead()).thenReturn(true);
assertThat(sut.method1(filePath), is(true));
// sad path 1
Mockito.when(file.exists()).thenReturn(false);
assertThat(sut.method1(filePath), is(false));
// sad path 2
Mockito.when(file.exists()).thenReturn(true);
Mockito.when(file.canRead()).thenReturn(false);
assertThat(sut.method1(filePath), is(false));

相关内容

  • 没有找到相关文章

最新更新