【问题标题】:Spock + Spring - Stubs returned from Stubbed @SpringBean always return nullSpock + Spring - 从 Stubbed @SpringBean 返回的存根始终返回 null
【发布时间】:2019-12-18 00:19:11
【问题描述】:

我正在尝试使用 Spock 围绕 Spring 应用程序创建集成测试。由于它不是 Spring Boot 应用程序,并且 @SpringBootTest 注释严重干扰了应用程序的初始化,因此我使用的是最小配置。

我特别需要在我的应用程序中存根一个返回 Message 类型对象的服务;在实际应用程序中,这些对象将来自第三方供应商的库,它们不能被实例化或子类化,它们的成员也没有设置器,所以我唯一的选择是为它们创建 Stubs。但是,使用当前的配置(我已经大大简化了测试,只是为了了解要点):

@ContextConfiguration([TestSetup]) // supplies actual Spring beans including some JPA repos
class LogicSpec extends Specification {
  @SpringBean
  RestService restService = Stub()
  @Autowired
  ServiceUnderTest sut
  @Autowired
  SomeJPARepo repository;

  def 'should do some business logic'() {
    given:
      Message m = new Stub() {
        getStatus() >> "stubbed status"
      }
      restService.getMessage(_ as String) >> {
        m
      }
    when:
      sut.businessMethod()
    then:
      // just checking for side effects that `businessMethod` causes, no mocks being matched against
      assert repository.findAll().every { it.processed == true }  
    }
  }
}

在内部,ServiceUnderTest.businessMethod() 使用 Message 对象,如下所示:

restService.getMessage(sid).getStatus() // should be "stubbed status"; always evaluates to null

然而,每个方法Message存根总是返回null,不管我是否为它定义了一个行为。 Message 对象必须从它的 getter 中返回特定值才能使测试工作。我宁愿不必将每个Message 存根声明为自己的@SpringBean;我最终需要扩展测试以使用几个不同的Message 存根对象。我不需要模拟或间谍,因为RestService 的方法的调用次数无关紧要,我只需要它为ServiceUnderTest 发出适当的存根来咀嚼。如果这个问题不寻常或者我错过了一些明显的东西,我们深表歉意;我有点忘记 Spock 的生命周期概念,而且随着 Spring 扩展的添加,水变得特别混乱。

【问题讨论】:

  • Message 具体是什么? (还要注意 assertthen 块中是不必要的,并且您通常不应该比较 Java 或 Groovy 中的布尔常量,所以只需 then: repository.findAll().every { it.processed }
  • (另外,这看起来真的是一个unit测试,那你为什么不直接使用new ServiceUnderTest(mockRepo, rest)呢?)
  • 我也有同样的问题。你有没有找到解决办法。所以请回答你自己的问题。

标签: java spring groovy spock


【解决方案1】:

写完这篇文章后我很快就找到了答案,但只是为了后代;第三方Message 类被声明为final,因此不能被子类化; Spock 正在为它们创建存根,但默默地没有添加被覆盖的模拟方法。我最终使用PowerMockito 来消除这个限制;但是这会干扰收集测试覆盖率指标,所以我改用了一个可以模拟的包装类,并在我的代码中到处使用它原来的 Message 类是:

public class MessageWrapper {
  public MessageWrapper(Message from) {...}
}

这有点让人头疼,但这是必要的,因为在这种情况下需要测试覆盖率。似乎还有一个很有前途的 Spock-specific mocking utility 可以模拟最终课程,但我没有测试过它,也不知道它是否会像 PowerMockito 那样干扰收集覆盖率指标。

【讨论】:

    猜你喜欢
    • 2018-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-31
    • 2015-08-15
    • 2012-03-18
    • 2016-11-04
    • 2016-07-28
    相关资源
    最近更新 更多