I am trying to test a class that will call another web service to fetch data if a null
value is provided. My JUnit + Mockito test works great, but I cannot get my Spock test to match in the then:
block. The error returned during the Spock test is:
Suppressed: java.lang.NullPointerException: Cannot invoke method map() on null object
Which is because my mocked method is not matching, and therefore returns null
.
Spock test (not working)
class MySpec extends Specfication {
def mockCollaboratingService = Mock(CollaboratingService)
def service = new MyService(collaboratingService: mockCollaboratingService)
def "should call another service if the provided start value equals null"() {
given:
def id = 123
def startDate = null
when: "the service is called"
def result = service.getTransactions(id, startDate)
then:
1 * mockCollaboratingService.getData(id) >> Mono.just(new SomeMockResponse(key: "123"))
StepVerifier
.create(result)
.consumeNextWith({
// assertions here
})
.verifyComplete()
}
}
JUnit + Mockito (working)
class AnotherSpec {
def mockCollaboratingService = Mockito.mock(MockCollaboratingService)
def service = new MyService(collaboratingService: mockCollaboratingService)
@Test
@DisplayName("should call the statement service if the given start date is null")
void shouldCallStatementServiceIfStartDateEqualsNull() {
def id = 123
def startDate = null
// and some fake data returned from the api
Mockito.when(mockCollaboratingService.getData(id)).thenReturn(Mono.just(new SomeMockResponse(key: "123")))
//when
def result = service.getTransactions(id, null)
//then
StepVerifier
.create(result)
.consumeNextWith({
Mockito.verify(mockStatementService, Mockito.times(1)).getLastStatement(enterpriseToken)
assert it.transactionId == 123
})
.verifyComplete()
}
}
Spock handles mocking differently than mockito, have a look at combining mocking and stubbing. Furthermore, all interactions must be finished before the then
block, as Spock verifies them as first thing. With reactor, it is actually StepVerifier
that is executing the code. The line def result = service.getTransactions(id, startDate)
only creates a cold Mono/Flux, but doesn't to anything.
So, you have to reorder your tests slightly.
class MySpec extends Specfication {
def mockCollaboratingService = Mock(CollaboratingService)
def service = new MyService(collaboratingService: mockCollaboratingService)
def "should call another service if the provided start value equals null"() {
given:
def id = 123
def startDate = null
when: "the service is called"
def result = service.getTransactions(id, startDate)
and: "code is executed"
StepVerifier
.create(result)
.consumeNextWith({
// no explicit mock assertions necessary
assert it.transactionId == 123
})
.verifyComplete()
then:
1 * mockCollaboratingService.getData(id) >> Mono.just(new SomeMockResponse(key: "123"))
}
}