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

时间:2018-02-14 09:28:19

标签: mocking mockito junit4 powermockito junit5

我有一个名为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())。

3 个答案:

答案 0 :(得分:2)

第一个答案是:你不能单凭Mockito。

您需要一个能够模拟对new的调用的模拟框架。如PowerMock(ito)或JMockit。您可以使用PowerMock here找到有关如何执行此操作的文档。从这个意义上讲,从技术上讲,这是一个已解决的问题 - 它只需要一些麻烦就可以使它工作(如果你得到一个pre-reqs错误,它根本就不起作用)。

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

因此,不要花费宝贵的时间来处理PowerMock(ito) - 请遵循您已经掌握的建议并修复测试问题的根本原因。例如,通过使用某种依赖注入来为此代码提供File对象(而不是让代码本身调用new)。

答案 1 :(得分:0)

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

紧密耦合
  

Explicit Dependencies Principle州:

     

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

考虑到这一点,请考虑重构该方法以明确依赖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);

答案 2 :(得分:0)

您可以使用JUnit的TemporaryFolder规则(或者,如果使用JUnit5,它的equivalent extension)来为您的测试创建输入文件。

然后你会......

  • 将此文件的路径传递到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));