如何使用 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(_)
}
我目前正在尝试为我创建的 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(_)
}