spock 集成测试_Spock 1.2 –轻松进行集成测试中的Spring Bean模拟

本文介绍了如何使用Spock 1.2在Spring上下文中进行集成测试,重点在于Spock模拟和间谍的自动注入。在Spock 1.2中,模拟和间谍的使用变得更加方便,类似于Spring Boot对Mockito的支持。虽然存在一些限制,如模拟实例在测试间的隔离,但Spock 1.2为Spring集成测试提供了更原生的模拟解决方案。
摘要由CSDN通过智能技术生成

spock 集成测试

探索如何使用Spock 1.2将Spock的模拟和间谍自动注入到Spring上下文中。

Spock中的存根/模拟/间谍(及其生命周期)一直与Spock Specification类紧密结合。 只能在测试类中创建它们。 因此,使用共享的,预定义的模拟(在单元测试和集成测试中)是有问题的。

这种情况在Spock 1.1中有所改善,但只有在基于Spring的集成测试中使用Spock模拟子系统的全新Spock 1.2(撰写本文时为1.2-RC1)时,与使用@SpringMock进行Spring @SpringMock一样容易开机 让我们检查一下。

顺便说一句,除了Spock 1.2-RC1之外,为了更前沿,我将使用Spring Boot 2.1.0.M2,Spring 5.1.0.RC2和Groovy 2.5.2(但所有功能都应在Spring的稳定版本中使用(引导)和Groovy 2.4)。

斯波克

还有一件事。 为了简单起见,在本文中,我将使用术语“模拟”来指代存根和间谍。 它们的行为有所不同 ,但是在Spock测试中将其注入Spring上下文的范围通常并不重要。

Spock 1.1 –手动方式

多亏了LeonardBrünings的工作,Spock中的模拟才脱离了Specification类。 最终可以在外部创建它们,然后将其附加到正在运行的测试中。 这是在Spring(或任何其他)上下文中使用Spock模拟的基础。

在此示例代码中,我们有ShipDatabase类,该类使用OwnShipIndexEnemyShipIndex (当然是由构造函数注入的:))来返回有关所有与名称匹配的已知船只的汇总信息。

//@ContextConfiguration just for simplification, @(Test)Configuration is usually more convenient for Spring Boot tests
//Real beans can exist in the context or not
@ContextConfiguration(classes = [ShipDatabase, TestConfig/*, OwnShipIndex, EnemyShipIndex*/])
class ShipDatabase11ITSpec extends Specification {

    private static final String ENTERPRISE_D = "USS Enterprise (NCC-1701-D)"
    private static final String BORTAS_ENTERA = "IKS Bortas Entera"

    @Autowired
    private OwnShipIndex ownShipIndexMock

    @Autowired
    private EnemyShipIndex enemyShipIndexMock

    @Autowired
    private ShipDatabase shipDatabase

    def "should find ship in both indexes"() {
        given:
            ownShipIndexMock.findByName("Enter") >> [ENTERPRISE_D]
            enemyShipIndexMock.findByName("Enter") >> [BORTAS_ENTERA]
        when:
            List<String> foundShips = shipDatabase.findByName("Enter")
        then:
            foundShips == [ENTERPRISE_D, BORTAS_ENTERA]
    }

    static class TestConfig {
        private DetachedMockFactory detachedMockFactory = new DetachedMockFactory()

        @Bean
        @Primary    //if needed, beware of consequences
        OwnShipIndex ownShipIndexStub() {
            return detachedMockFactory.Stub(OwnShipIndex)
        }

        @Bean
        @Primary    //if needed, beware of consequences
        EnemyShipIndex enemyShipIndexStub() {
            return detachedMockFactory.Stub(EnemyShipIndex)
        }
    }
}

这些模拟是在单独的类中(在Specification之外)创建的,因此必须使用DetachedMockFactory (或使用SpockMockFactoryBean )。 这些模拟必须被附加(和分离)到测试实例( Specification实例),但是由spock-spring模块(从1.1版本开始)会自动处理。 对于从外部创建的通用MockUtil.attachMock() ,还需要使用MockUtil.attachMock()mockUtil.detachMock()使其起作用。

结果,可以在Spring上下文中创建和使用模拟,但是它不是很方便,也不常用。

Spock 1.2 –一流的支持

Spring Boot 1.4通过(Mockito)的模拟为集成测试带来了新的质量。 它利用了最初于2012年在Springockito中提出的想法(当时Spring配置主要是用XML编写的:))将模拟(或间谍)自动注入到Spring(引导)上下文中。 Spring Boot团队扩展了这个想法,并且由于有了它作为内部支持的功能(通常),因此只需在测试中添加一个或两个注释即可可靠地工作。

Spock 1.2中内置了类似的基于注释的机制。

//@ContextConfiguration just for simplification, @(Test)Configuration is usually more convenient for Spring Boot tests
//Real beans can exist in the context or not
@ContextConfiguration(classes = [ShipDatabase/*, OwnShipIndex, EnemyShipIndex*/])
class ShipDatabaseITSpec extends Specification {

    private static final String ENTERPRISE_D = "USS Enterprise (NCC-1701-D)"
    private static final String BORTAS_ENTERA = "IKS Bortas Entera"

    @SpringBean
    private OwnShipIndex ownShipIndexMock = Stub()  //could be Mock() if needed

    @SpringBean
    private EnemyShipIndex enemyShipIndexMock = Stub()

    @Autowired
    private ShipDatabase shipDatabase

    def "should find ship in both indexes"() {
        given:
            ownShipIndexMock.findByName("Enter") >> [ENTERPRISE_D]
            enemyShipIndexMock.findByName("Enter") >> [BORTAS_ENTERA]
        when:
            List<String> foundShips = shipDatabase.findByName("Enter")
        then:
            foundShips == [ENTERPRISE_D, BORTAS_ENTERA]
    }
}

没有太多要添加的内容。 @SpringBean指示Spock将模拟注入到Spring上下文中。 类似地, @SpringSpy用间谍包装真实的bean。 在@SpringBean的情况下,需要初始化一个字段以让Spock知道我们打算使用存根还是模拟。

另外,还有一个更通用的注释@StubBeans ,以存根替换所有已定义的bean。 但是,我计划在另一篇博客文章中单独介绍它。

局限性

对于那些希望在本文演讲后立即在您的Spock测试中将所有Mockito的模拟重写为Spock的模拟的人来说,这是一个警告。 Spock的模拟物-由于其性质和与Specification关系-具有某些局限性。 在幕后的实现创建了一个代理,该代理被注入到Spring上下文中(可能)替换实际的bean(存根/模拟)或包装它们(间谍)。 该代理在特定测试(规范)类中的所有测试之间共享。 实际上,在Spring能够缓存上下文的情况下,它也可以跨越具有相同bean / mock声明的其他测试(与Mockito的模拟或一般的Spring集成测试类似的情况)。

但是,真正重要的是,代理在执行之前就已连接到测试,并在执行之后被分离。 因此,实际上,每个测试都有其自己的模拟实例(不能应用于@Shared字段),例如,将来自不同测试的交互分组并一起验证它们是有问题的(通常是非常明智的,但可能会导致某些情况)复制)。 但是,使用setup块(或在线存根)可以共享存根和交互预期。

摘要

Spock 1.2最终带来了轻松的Spock存根/模拟/间谍支持,以便在Spring上下文中使用它们,这与Spring Boot中为Mockito提供的支持相当。 将spock-spring模块添加到项目(运行时)依赖项就足够了。 尽管有一些限制,但在Spock(集成)测试中将本机Spock的模拟子系统与外部模拟框架(例如Mockito)混合起来要少一点。 不错的是,它也应该在普通的Spring Framework测试中起作用(不仅是Spring Boot测试)。 Guice已实现了相同的功能(但我尚未对其进行测试)。

此外,Spock 1.2还带来了其他一些更改,包括对Java 9+的更好支持,值得在您的测试套件中进行尝试(当然,请报告任何可能发现的回归错误:))。

还有一个好消息。 除了使Spock 1.2成为可能的伦纳德的工作以及大量的错误报告者和PR贡献者之外,最近以来,还有其他一些提交者正在致力于使Spock变得更好。 您可能从其他一些流行的FOSS项目中了解了其中一些。 而且,Spock 1.2 (初步)计划成为基于JUnit 4的最后一个版本,而下一个稳定的Spock版本可能是2.0,这是利用JUnit 5及其(以及其他)并行运行测试的本机能力。

这些示例是使用Spock 1.2-RC1编写的。 一旦发布,它将更新为1.2-final。 源代码可从GitHub获得。

翻译自: https://www.javacodegeeks.com/2018/09/spock-spring-beans-mocking-integration.html

spock 集成测试

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值