Reputation: 760
I have a simple class that builds a RequestMessage
based on a simple rule.
MessageMetadata
is found in the database, the message is built using that metadata.Here is the class along with a Spock test. The test fails with a MissingPropertyException
, saying it cannot find the RequestMessage
created using the service.
class MessageService{
MessageBuilder messageBuilder;
MessageRepository messageRepository;
MessageMetadaProvider messageMetaDataProvider;
public RequestMessage getMessage(String id ) {
try {
MessageMetadata metadata = repository.findDefaulMessage(id);
RequestMessage requestMessage = builder.createMessage(metadata);
return requestMessage;
} catch (DataNotFoundException e) {
e.printStackTrace();
}
MessageMetadata metadata = messageMetaDataProvider.createNewMessageMetadata(id);
RequestMessage message = messageBuilder.buildNew(id , metadata);
return message;
}
}
def "Build Request Message "() {
given:
String id = '12345'
MessageBuilder messageBuilder = Mock()
MessageRepository messageRepository = Mock()
MessageMetadaProvider messageMetaDataProvider = Mock()
MessageService service = createMessageService(messageRepository,messageBuilder,messageMetaDataProvider)
MessageMetadata metadata = new MessageMedata(id, MessageType.DEFAULT)
when:
RequestMessage requestMessage = messageService .getMessage(id )
then:
1 * messageRepository.repository.findDefaulMessage(id) >> {throw new DataNotFoundException("Not Found")}
1 * messageMetaDataProvider.createNewMessageMetadata(id) >> metadata
1 * messageBuilder.buildNew(id , metadata) >> requestMessage
}
I would really like to understand why this doesn't work. I'm grateful for any help in testing this test successfully. Thank you
Upvotes: 3
Views: 1334
Reputation: 67287
The problem is indeed the hen vs. egg problem I mentioned in my comment to jaco0646's answer. Let me recreate the core problem in an MCVE:
package de.scrum_master.stackoverflow.q60143388;
public class RequestMessage {}
package de.scrum_master.stackoverflow.q60143388;
public class MessageService {
MessageBuilder messageBuilder;
public RequestMessage getMessage(String id) {
return messageBuilder.buildNew(id);
}
}
package de.scrum_master.stackoverflow.q60143388
import spock.lang.Specification
class MessageServiceTest extends Specification {
def "build request message"() {
given:
def id = "12345"
MessageBuilder messageBuilder = Mock()
MessageService messageService = new MessageService()
messageService.messageBuilder = messageBuilder
when:
RequestMessage requestMessage = messageService.getMessage(id)
then:
1 * messageBuilder.buildNew(id) >> requestMessage
}
}
This will yield:
groovy.lang.MissingPropertyException: No such property: requestMessage for class: de.scrum_master.stackoverflow.q60143388.MessageServiceTest
at de.scrum_master.stackoverflow.q60143388.MessageServiceTest.build request message(MessageServiceTest.groovy:17)
Just declaring requestMessage
in the given:
block as jaco0646 suggested and then using it as a stub result won't do it alone. You need to make sure that you first declare an object (e.g. a mock) to be returned by the builder method, but assign the result of the method call under test to another variable so you can compare the two or do whatever verification you like to perform:
package de.scrum_master.stackoverflow.q60143388
import spock.lang.Specification
class MessageServiceTest extends Specification {
def "build request message"() {
given:
def id = "12345"
RequestMessage requestMessage = Mock()
MessageBuilder messageBuilder = Mock()
MessageService messageService = new MessageService()
messageService.messageBuilder = messageBuilder
when:
RequestMessage result = messageService.getMessage(id)
then:
1 * messageBuilder.buildNew(id) >> requestMessage
result.toString().startsWith("Mock for type 'RequestMessage'")
}
}
Now the test passes and your bootstrapping problem is solved. You cannot create an object with a method call and then specify it as an expected stub result at the same time. It makes no logical sense.
Upvotes: 2
Reputation: 17066
Try declaring requestMessage
in the given
block rather than the when
block.
The Spock lifecycle has some surprising behaviors, one of which is that interactions are processed before the when
block.
Upvotes: 1