如何使用Mockito

时间:2017-06-29 18:45:27

标签: java junit mockito

我的实用程序中有一个方法:

public void createDirectories(final Path root, final Scaffolding scaffolding) throws FileAlreadyExistsException {
    if (Files.exists(root)) {
        throw new FileAlreadyExistsException("Root directory " + root.toString() + " already exists.");
    } else {
        Files.createDirectories(root);
        // Create directories from the scaffolding object
    }
}

我想模仿Files,以便我可以测试以确保调用预期字段Files.createDirectories

我可以和Mockito一起做吗?或者我是否需要实际创建目录并检查它们是否存在于某个tmp文件夹中?

3 个答案:

答案 0 :(得分:1)

您可以使用JUnit @Rule来创建一个临时文件夹,在测试执行完成(或失败)后将删除该文件夹:

public class TestTemporaryFolderRule {
    @Rule
    public TemporaryFolder testFolder = new TemporaryFolder();

    @Test
    public void testInTempFolder() throws IOException {
        File tempFolder = testFolder.newFolder("test");
        // test...
    }
}

答案 1 :(得分:1)

当你用tdd写东西并遇到麻烦时,将其视为糟糕设计的信号。你不需要模拟静态字段或找到一些棘手的lib来做它。而不是这样做make代表文件系统的实体,并将与文件操作相关的所有方法放在这个类中。有了这个重构,你的代码将是这样的:

class UtilClass { //util classes are bad don't do it
    private final FileSystem fileSystem;

    public UtilClass(FileSystem fileSystem) {
        this.fileSystem = fileSystem;
    }


    public void createDirectories(final Path root, final Scaffolding scaffolding) throws FileAlreadyExistsException {
        if (fileSystem.exists(root)) {
            throw new FileAlreadyExistsException("Root directory " + root.toString() + " already exists.");
        } else {
            fileSystem.createDirectories(root);
            // Create directories from the scaffolding object
    }




interface FileSystem {

    boolean exists(Path path);

    void createDirectories(Path path);
}

和测试类

class UtilClassTest {


        @Test(expected = FileAlreadyExistsException.class)
        public void shouldThrowExceptionWhenRootPathExists() {
            FileSystem mockFileSystem = Mockito.mock(FileSystem.class);
            Mockito.when(mockFileSystem.exists(anyPath())).return(true);
            UtilClass util = new UtilClass(mockFileSystem);
            util.createDirectories(mock(Path.class), mock(Scaffolding.class))
        }
    }

在您的代码外部测试中将mock替换为实现。

class FileSystemImpl implements FileSystem {

    boolean exists(Path path){
        return Files.exists(path);
    }

    createDirectories(Path path){
        return Files.createDirectories(path);
    }

} 

并且您不需要在测试或模拟静态字段中触摸文件系统。

答案 2 :(得分:0)

您不能使用基本Mockito模拟静态方法,在大多数情况下,您也不能,尤其是Java提供的方法。您可以使用PowerMock模拟静态方法,但这是一个全局核心库。

您在此处测试的一段代码是,如果目录存在,您是否会收到异常。如果Files.exists()返回错误结果,则您的程序会以任何方式烘烤。因此,您应该最终测试的是,正在根据完全实现的Files全局执行流程,正确地遵循流程。

@Test
public void testCreateDirectories() {

    File tempFile = new File("test");
    tempFile.delete(); //delete test directory if it exists     
    tempFile.deleteOnExit(); //and again when the test finishes

    Path testPath = tempFile.getPath();

    foo.createDirectories(testPath, mock(Scaffolding.class)); //should create path
    Assert.assertTrue(tempFile.exists());

    try {
        foo.createDirectories(testPath, mock(Scaffolding.class)); //should FAE
        Assert.fail(Should have thrown an FAE exception at this point!);
    }
    catch(FileAlreadyExistsException faee) {
        logger.debug("Expected FAE exception thrown", faee);
    }
}

此执行将遍历true和false路径并自行清理。

逻辑的这种双重执行测试两个路径,并且如果您的if语句设置为混乱,则设计用于涵盖以下方案。

  • boolean按预期工作:两个调用都工作,PASS
  • boolean意外倒置:第一个电话抛出FAE,FAIL
  • boolean总是返回false:第二次调用不会抛出FAE,FAIL。
  • boolean总是返回true:第一个调用抛出FAE,FAIL。