javascript
Spock 1.2 –轻松进行集成测试中的Spring Bean模拟
探索如何使用Spock 1.2將Spock的模擬和間諜自動(dòng)注入到Spring上下文中。
Spock中的存根/模擬/間諜(及其生命周期)一直與Spock Specification類緊密結(jié)合。 只能在測(cè)試類中創(chuàng)建它們。 因此,使用共享的預(yù)定義模擬(在單元測(cè)試和集成測(cè)試中)是有問(wèn)題的。
這種情況在Spock 1.1中有所改善,但只有在基于Spring的集成測(cè)試中使用Spock模擬子系統(tǒng)的全新Spock 1.2(撰寫本文時(shí)為1.2-RC1)時(shí),與在Spring中對(duì)Mockito模擬使用@SpringMock一樣容易開(kāi)機(jī) 讓我們檢查一下。
順便說(shuō)一句,除Spock 1.2-RC1之外,為了更前沿,我將使用Spring Boot 2.1.0.M2,Spring 5.1.0.RC2和Groovy 2.5.2(但所有功能都應(yīng)在Spring的穩(wěn)定版本中使用(引導(dǎo))和Groovy 2.4)。
還有一件事。 為了簡(jiǎn)單起見(jiàn),在本文中,我將使用術(shù)語(yǔ)“模擬”來(lái)指代存根和間諜。 它們的行為有所不同 ,但是在Spock測(cè)試中將其注入Spring上下文的范圍通常并不重要。
Spock 1.1 –手動(dòng)方式
多虧了LeonardBrünings的工作,Spock中的模擬才脫離了Specification類。 最終可以在外部創(chuàng)建它們,然后將其附加到正在運(yùn)行的測(cè)試中。 這是在Spring(或任何其他)上下文中使用Spock模擬的基礎(chǔ)。
在此示例代碼中,我們具有ShipDatabase類,該類使用OwnShipIndex和EnemyShipIndex (當(dāng)然是由構(gòu)造函數(shù)注入的:))來(lái)返回有關(guān)所有與名稱匹配的已知船只的匯總信息。
//@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"@Autowiredprivate OwnShipIndex ownShipIndexMock@Autowiredprivate EnemyShipIndex enemyShipIndexMock@Autowiredprivate ShipDatabase shipDatabasedef "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 consequencesOwnShipIndex ownShipIndexStub() {return detachedMockFactory.Stub(OwnShipIndex)}@Bean@Primary //if needed, beware of consequencesEnemyShipIndex enemyShipIndexStub() {return detachedMockFactory.Stub(EnemyShipIndex)}} }這些模擬是在單獨(dú)的類中(在Specification之外)創(chuàng)建的,因此必須使用DetachedMockFactory (或使用SpockMockFactoryBean )。 這些模擬必須附加(和分離)到測(cè)試實(shí)例( Specification實(shí)例),但是它由spock-spring模塊(從1.1版本開(kāi)始)自動(dòng)處理。 對(duì)于從外部創(chuàng)建的通用MockUtil.attachMock() ,還需要使用MockUtil.attachMock()和mockUtil.detachMock()使其起作用。
結(jié)果,可以在Spring上下文中創(chuàng)建和使用模擬,但是它不是很方便,也不常用。
Spock 1.2 –一流的支持
Spring Boot 1.4通過(guò)(Mockito的)模擬為集成測(cè)試帶來(lái)了新的質(zhì)量。 它利用了最初于2012年在Springockito中提出的想法(當(dāng)時(shí)Spring配置主要是用XML編寫的:))將模擬(或間諜)自動(dòng)注入到Spring(引導(dǎo))上下文中。 Spring Boot團(tuán)隊(duì)擴(kuò)展了這個(gè)想法,并且由于有了它作為內(nèi)部支持的功能(通常),因此只需在測(cè)試中添加一個(gè)或兩個(gè)注釋即可可靠地工作。
Spock 1.2中內(nèi)置了類似的基于注釋的機(jī)制。
//@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"@SpringBeanprivate OwnShipIndex ownShipIndexMock = Stub() //could be Mock() if needed@SpringBeanprivate EnemyShipIndex enemyShipIndexMock = Stub()@Autowiredprivate ShipDatabase shipDatabasedef "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]} }沒(méi)有太多要添加的內(nèi)容。 @SpringBean指示Spock將模擬注入到Spring上下文中。 類似地, @SpringSpy用間諜包裝真實(shí)的bean。 在@SpringBean的情況下,需要初始化一個(gè)字段以讓Spock知道我們打算使用存根還是模擬。
此外,還有一個(gè)更通用的批注@StubBeans ,用存根替換所有已定義的bean。 但是,我計(jì)劃在另一篇博客文章中單獨(dú)介紹它。
局限性
對(duì)于那些希望在本文演講后立即在您的Spock測(cè)試中將所有Mockito的模擬重寫為Spock的模擬的人來(lái)說(shuō),這是一個(gè)警告。 Spock的模擬物-由于其性質(zhì)和與Specification關(guān)系-具有某些局限性。 幕后的實(shí)現(xiàn)創(chuàng)建了一個(gè)代理,該代理被注入到Spring上下文中(可能)替換真實(shí)的bean(存根/模擬)或包裝它們(間諜)。 該代理在特定測(cè)試(規(guī)范)類中的所有測(cè)試之間共享。 實(shí)際上,在Spring能夠緩存上下文的情況下,它也可以跨越具有相同bean / mock聲明的其他測(cè)試(與Mockito的模擬或通常的Spring集成測(cè)試類似的情況)。
但是,真正重要的是,代理在執(zhí)行之前即被附加到測(cè)試,并在執(zhí)行之后被分離。 因此,實(shí)際上,每個(gè)測(cè)試都有其自己的模擬實(shí)例(不能應(yīng)用于@Shared字段),例如將來(lái)自不同測(cè)試的交互分組并一起驗(yàn)證它們是有問(wèn)題的(通常是很明智的,但可能會(huì)導(dǎo)致某些情況)復(fù)制)。 但是,使用setup塊(或在線存根)可以共享存根和交互期望。
摘要
Spock 1.2最終帶來(lái)了輕松的Spock存根/模擬/間諜支持,以便在Spring上下文中使用它們,這與Spring Boot中為Mockito提供的存根相當(dāng)。 將spock-spring模塊添加到項(xiàng)目(運(yùn)行時(shí))依賴項(xiàng)就足夠了。 盡管有一些限制,但在Spock(集成)測(cè)試中將本機(jī)Spock的模擬子系統(tǒng)與外部模擬框架(例如Mockito)混合使用,卻少了一點(diǎn)。 不錯(cuò)的是,它也應(yīng)該在普通的Spring Framework測(cè)試(不僅是Spring Boot測(cè)試)中工作。 Guice已實(shí)現(xiàn)了相同的功能(但我尚未對(duì)其進(jìn)行測(cè)試)。
此外,Spock 1.2還帶來(lái)了其他一些變化,包括對(duì)Java 9+的更好支持,值得在您的測(cè)試套件中進(jìn)行嘗試(當(dāng)然,請(qǐng)報(bào)告任何可能發(fā)現(xiàn)的回歸bug :)。
還有一個(gè)好消息。 除了使Spock 1.2成為可能的倫納德的工作以及大量的錯(cuò)誤報(bào)告者和PR貢獻(xiàn)者之外,最近以來(lái),還有其他一些提交者正在致力于使Spock變得更好。 您可能從其他一些流行的FOSS項(xiàng)目中了解了其中一些。 而且,Spock 1.2 (初步)計(jì)劃成為基于JUnit 4的最后一個(gè)版本,而下一個(gè)穩(wěn)定的Spock版本可能是2.0,這是利用JUnit 5及其(以及其他)并行運(yùn)行測(cè)試的本機(jī)能力。
這些示例是使用Spock 1.2-RC1編寫的。 一旦發(fā)布,它將更新為1.2-final。 源代碼可從GitHub獲得。
翻譯自: https://www.javacodegeeks.com/2018/09/spock-spring-beans-mocking-integration.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的Spock 1.2 –轻松进行集成测试中的Spring Bean模拟的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Omdia:英伟达二季度出货900吨H1
- 下一篇: Jib –为Spring Boot应用程