如何使用 Spock 模拟一个 class 有一个 returns 什么都没有的方法

How to mock a class that has a method that returns nothing, using Spock

我目前正在尝试为我创建的 class 设置 Spock 测试,该测试有一个 returns 没有的方法。

public final class Test implements ITest {

    private static Logger logger = LoggerFactory.getLogger(test.class);

    private DataSource testSource;

    public Test(DataSource testSource) {
        testSource = testSource;
    }

    public void validateFile() {

        if (logger.isDebugEnabled()) {
            logger.debug("validating file");
        }

        Handler handler = new Handler();
        handler.getValues(testSource);
    }
}

以上是我要 Spock 测试的测试,我只想测试这个 class 而不是具有方法 getValues 的处理程序 class。

这是我的模拟测试 class:

def "test buildConfig"() {
    given:
    DataSource testSource = Mock()
    Handler handler = Mock()
    Test test = new Test(testSource)
    when:
    test.validateFile()
    then:
    1 * handler.getValues(_)
}

但是我得到一个空指针异常,因为 handler.getValues 似乎在我没有提供的那个方法中做了一些逻辑。但我不关心 class:我只是想测试当我在测试 class 中 运行 validateFile 方法时,它会创建一个处理程序并调用处理程序上的 getValues 方法。

因为您的 class 创建了自己的 new Handler(),所以它没有使用您创建的 Mock。

为了能够验证这一点,您需要重构 class 以使其更易于测试。

传入处理程序

首先,让我们看一下将 Handler 传递给方法:

public final class Test implements ITest {

    private static Logger logger = LoggerFactory.getLogger(test.class);

    private DataSource testSource;

    public Test(DataSource testSource) {
        testSource = testSource;
    }

    public void validateFile(Handler handler) {

        if (logger.isDebugEnabled()) {
            logger.debug("validating file");
        }

        handler.getValues(testSource);
    }
}

现在我们可以将我们的 mock 传递到我们的 validateFile 调用中并成功验证它:

def "test buildConfig"() {
    given: 'a datasource, handler and Test'
    DataSource testSource = Mock()
    Handler handler = Mock()
    Test test = new Test(testSource)

    when: 'we validate our file'
    test.validateFile(handler)

    then: 'our handler was invoked'
    1 * handler.getValues(_)
}

使用供应商

如果我们真的想在方法内部创建处理程序,那么我们可以根据@leonard-brünings

的评论传入一个Supplier<Handler>

作为更改 verifyFile() 签名的替代方法,这一次,让我们重写我们的构造函数以将 Supplier 作为参数并将我们的函数存储为字段:

public final class Test implements ITest {

    private static Logger logger = LoggerFactory.getLogger(test.class);

    private DataSource testSource;
    private Supplier<Handler> supplierOfHandler;

    public Test(DataSource testSource, Supplier<Handler> handlerSupplier) 
    {
        testSource = testSource;
        supplierOfHandler = handlerSupplier;
    }

    public void validateFile() {

        if (logger.isDebugEnabled()) {
            logger.debug("validating file");
        }
        handler = supplierOfHandler.get()
        handler.getValues(testSource);
    }
}

... 然后与供应商一起设置我们的测试 returns 模拟处理程序,然后我们可以使用它来验证交互:

def "test buildConfig"() {
    given: 'a datasource, handler and Test'
    DataSource testSource = Mock()
    Handler handler = Mock()
    Test test = new Test(testSource, () -> handler)

    when: 'we validate our file'
    test.validateFile()

    then: 'our handler was invoked'
    1 * handler.getValues(_)
}