【问题标题】:Spock Test Failing with MissingPropertyExceptionSpock 测试失败并出现 MissingPropertyException
【发布时间】:2020-05-25 08:34:47
【问题描述】:

我有一个简单的类,它基于一个简单的规则构建一个RequestMessage

  • 如果在数据库中找到MessageMetadata,则使用该元数据构建消息。
  • 否则,将使用提供元数据的服务构建消息。

这是课程以及 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
}

我真的很想了解为什么这不起作用。对于成功测试此测试的任何帮助,我表示感谢。谢谢

【问题讨论】:

  • 带有许多依赖类的代码不构成MCVE。此外,您的示例类中存在不一致,例如messageBuilderbuildermessageRepositoryrepository。然后在你的测试中有messageRepository.repository 好像messageRepository 有一个属性或getter 也命名为repository 这至少会很奇怪。

标签: java unit-testing spock


【解决方案1】:

问题确实是我在对 jaco0646 的回答的评论中提到的母鸡与鸡蛋问题。让我在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
  }
}

这将产生:

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)

仅仅在given: 块中声明requestMessage 就像jaco0646 建议的那样,然后将其用作存根结果不会单独完成。你需要确保你首先声明了一个对象(例如一个模拟)要由构建器方法返回,但是将被测方法调用的结果分配给另一个变量,这样你就可以比较两者或做任何你喜欢的验证执行:

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'")
  }
}

现在测试通过了,您的引导问题也解决了。您不能使用方法调用创建对象,然后同时将其指定为预期的存根结果。这没有逻辑意义。

【讨论】:

  • 谢谢,我不知道。我真的很感激这一点,它可以按照您的要求工作。感谢所有其他建议,非常感谢!
【解决方案2】:

尝试在given 块而不是when 块中声明requestMessage

Spock lifecycle 有一些令人惊讶的行为,其中之一是interactionswhen 块之前处理

【讨论】:

  • 您能否更好地解释问题所在并提供一个示例,而不仅仅是说“试试这个”。也许你是对的,但我不明白你的解释。您是否可能指的是OP想要在buildNew()中创建一个返回requestMessage的存根,然后在when:块中实际创建requestMessage,这将是一种母鸡与鸡蛋的问题?
猜你喜欢
  • 1970-01-01
  • 2015-10-07
  • 1970-01-01
  • 2015-05-28
  • 2021-11-16
  • 1970-01-01
  • 2014-12-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多