如何使用Spock Spy?

3

我尝试使用Spy测试,但失败了。以下类是Sut。

public class FileManager {
    public int removeFiles(String directory)    {
        int count = 0;
        if(isDirectory(directory))  {
            String[] files = findFiles(directory);
            for(String file : files)    {
                deleteFile(file);
                count++;
            }
        }
        return count;
    }

    private boolean isDirectory(String directory) {
        return directory.endsWith("/");
    }

    private String[] findFiles(String directory) {
        // read files from disk.
        return null;
    }

    private void deleteFile(String file)    {
        // delete a file.
        return;
    }
}

然后,我创建了以下类似的测试。

class SpyTest extends Specification  {
def "Should return the number of files deleted"()   {
    given:
    def fileManager = Spy(FileManager)
    1 * fileManager.findFiles("directory/") >> { return ["file1", "file2", "file3", "file4"] }
    fileManager.deleteFile(_) >> { println "deleted file."}

    when:
    def count = fileManager.removeFiles("directory/")

    then:
    count == 4
}

但是我遇到了空指针异常。
java.lang.NullPointerException
at example.spock.mock.FileManager.removeFiles(FileManager.java:8)
at net.sf.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
at org.spockframework.mock.runtime.CglibRealMethodInvoker.respond(CglibRealMethodInvoker.java:32)
at org.spockframework.mock.runtime.MockInvocation.callRealMethod(MockInvocation.java:60)
at org.spockframework.mock.CallRealMethodResponse.respond(CallRealMethodResponse.java:29)
at org.spockframework.mock.runtime.MockController.handle(MockController.java:49)
at org.spockframework.mock.runtime.JavaMockInterceptor.intercept(JavaMockInterceptor.java:72)
at org.spockframework.mock.runtime.CglibMockInterceptorAdapter.intercept(CglibMockInterceptorAdapter.java:30)
at example.spock.mock.SpyTest.Should return the number of files deleted(SpyTest.groovy:13)

这意味着实际的方法已被调用。它为什么不能正常工作?
1个回答

1
在 Spock 中,您无法模拟 Java 类的私有方法。查看您的 FileManager,不清楚为什么只有 removeFiles 是公共的,而其他方法是私有的。虽然所有方法都与文件管理相关。可能的解决方案如下:
  1. 将其余的 FileManager 方法设置为公共方法。这样,Spock 将起作用,FileManager 实际上将成为文件管理器,而不仅仅是文件删除器。
  2. FileManager 分解为不同的组件。因此,您可以单独模拟这些组件并将它们注入到“文件删除器”中。基本上,您已经在方法级别上分解了代码。但是,在 Spock 中无法模拟私有 Java 方法(链接1)。而且类分解可能是开销,因为 FileManager 看起来具有所有操作的内聚性。
  3. 使用其他测试/模拟框架来模拟私有方法。例如 mockito 和 powermock。但是,模拟私有方法是最糟糕的选择,因为如果失控,它会损害整个代码库的可维护性。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接