如何用mockito模拟文件静态方法

mxg2im7a  于 2021-06-27  发布在  Java
关注(0)|答案(2)|浏览(673)

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

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文件夹中?

hgqdbh6s

hgqdbh6s1#

当你用tdd写东西,遇到麻烦时,就把它看作是设计不好的信号。您不需要模拟静态字段或找到一些棘手的lib来完成它。与其这样做,不如创建表示文件系统的实体,并将与文件操作相关的所有方法放置到此类中。通过此重构,您的代码将如下所示:

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);
    }

}

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

6yjfywim

6yjfywim2#

不能用基本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);
    }
}

这个执行过程将通过正确和错误的路径,并在执行之后进行清理。
这种逻辑的双重执行测试了这两条路径,并设计用于在您的 if 声明设法搞砸了。
布尔值按预期工作:两个调用都工作,传递
布尔值意外反转:第一个调用抛出fae,失败
布尔值总是返回false:第二个调用不抛出fae,失败。
布尔值总是返回true:1st调用抛出fae,fail。

相关问题