I am currently attempting to set up Spock testing for a class that I created that has a method that returns nothing.
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);
}
}
Above is the test I want to Spock test, and I only want to test this class and not the Handler class that has the method getValues.
This is my test mock class:
def "test buildConfig"() {
given:
DataSource testSource = Mock()
Handler handler = Mock()
Test test = new Test(testSource)
when:
test.validateFile()
then:
1 * handler.getValues(_)
}
But I get a null pointer exception, because handler.getValues does some logic in that method that I have not provided, it seems. But I don't care about the class: I just want to test that when I run validateFile method in test class, it creates a Handler and calls the getValues method on the handler.
Because your class creates its own new Handler()
, it's not using the Mock you created.
To be able to verify this, you'll need to refactor your class to be more testable.
First, let's look at passing a Handler into the method:
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);
}
}
Now we can pass our mock into our validateFile call and verify it successfully:
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(_)
}
If we really want the Handler to be created inside the method, then we can pass in a Supplier<Handler>
as per the comment from @leonard-brünings
As an alternative to changing the verifyFile() signature, this time, let's rewrite our constructor to take a Supplier as an argument and store our function as a field:
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);
}
}
... and then set up our test with a supplier that returns a Mock Handler, that we can then use to verify interactions:
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(_)
}