Spock 测试因 MissingPropertyException 而失败
Spock Test Failing with MissingPropertyException
我有一个简单的 class,可以根据简单的规则构建 RequestMessage
。
- 如果在数据库中找到
MessageMetadata
,则消息是使用该元数据构建的。
- 否则,消息是使用提供元数据的服务构建的。
这是 class 以及 Spock 测试。测试失败并显示 MissingPropertyException
,表示无法找到使用该服务创建的 RequestMessage
。
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
}
我真的很想知道为什么这行不通。对于成功测试此测试的任何帮助,我深表感谢。谢谢
尝试在 given
块而不是 when
块中声明 requestMessage
。
Spock lifecycle has some surprising behaviors, one of which is that interactions 在 when
块之前 被处理。
问题确实是我在对 jaco0646 的回答的评论中提到的母鸡与鸡蛋的问题。让我在 MCVE:
中重现核心问题
package de.scrum_master.Whosebug.q60143388;
public class RequestMessage {}
package de.scrum_master.Whosebug.q60143388;
public class MessageService {
MessageBuilder messageBuilder;
public RequestMessage getMessage(String id) {
return messageBuilder.buildNew(id);
}
}
package de.scrum_master.Whosebug.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
}
}
这将产生:
groovy.lang.MissingPropertyException: No such property: requestMessage for class: de.scrum_master.Whosebug.q60143388.MessageServiceTest
at de.scrum_master.Whosebug.q60143388.MessageServiceTest.build request message(MessageServiceTest.groovy:17)
只是按照 jaco0646 的建议在 given:
块中声明 requestMessage
然后将其用作存根结果不会单独完成。您需要确保首先声明一个对象(例如模拟)由构建器方法返回,但是将被测方法调用的结果分配给另一个变量,以便您可以比较两者或进行任何您喜欢的验证执行:
package de.scrum_master.Whosebug.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'")
}
}
现在测试通过了,你的引导问题也解决了。您不能使用方法调用创建对象,然后同时将其指定为预期的存根结果。这没有逻辑意义。
我有一个简单的 class,可以根据简单的规则构建 RequestMessage
。
- 如果在数据库中找到
MessageMetadata
,则消息是使用该元数据构建的。 - 否则,消息是使用提供元数据的服务构建的。
这是 class 以及 Spock 测试。测试失败并显示 MissingPropertyException
,表示无法找到使用该服务创建的 RequestMessage
。
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
}
我真的很想知道为什么这行不通。对于成功测试此测试的任何帮助,我深表感谢。谢谢
尝试在 given
块而不是 when
块中声明 requestMessage
。
Spock lifecycle has some surprising behaviors, one of which is that interactions 在 when
块之前 被处理。
问题确实是我在对 jaco0646 的回答的评论中提到的母鸡与鸡蛋的问题。让我在 MCVE:
中重现核心问题package de.scrum_master.Whosebug.q60143388;
public class RequestMessage {}
package de.scrum_master.Whosebug.q60143388;
public class MessageService {
MessageBuilder messageBuilder;
public RequestMessage getMessage(String id) {
return messageBuilder.buildNew(id);
}
}
package de.scrum_master.Whosebug.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
}
}
这将产生:
groovy.lang.MissingPropertyException: No such property: requestMessage for class: de.scrum_master.Whosebug.q60143388.MessageServiceTest
at de.scrum_master.Whosebug.q60143388.MessageServiceTest.build request message(MessageServiceTest.groovy:17)
只是按照 jaco0646 的建议在 given:
块中声明 requestMessage
然后将其用作存根结果不会单独完成。您需要确保首先声明一个对象(例如模拟)由构建器方法返回,但是将被测方法调用的结果分配给另一个变量,以便您可以比较两者或进行任何您喜欢的验证执行:
package de.scrum_master.Whosebug.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'")
}
}
现在测试通过了,你的引导问题也解决了。您不能使用方法调用创建对象,然后同时将其指定为预期的存根结果。这没有逻辑意义。