javascript
使用Spring Boot隔离集成测试和模拟依赖项
集成測試可能很慢且不可靠,因?yàn)樗鼈円蕾囉谙到y(tǒng)中過多的組件。 在某種程度上,這是不可避免的:這里的集成測試是為了驗(yàn)證系統(tǒng)的每個(gè)部分如何與其他內(nèi)部或外部組件一起玩。
但是,我們可以通過僅分解所需的依賴關(guān)系而不是整個(gè)系統(tǒng)來改進(jìn)某些集成測試。 讓我們想象一個(gè)依賴于數(shù)據(jù)庫,第三方REST API和消息隊(duì)列的應(yīng)用程序:
現(xiàn)在假設(shè)我們希望集成測試驗(yàn)證僅包含對(duì)REST API的調(diào)用但不包含對(duì)數(shù)據(jù)庫或消息隊(duì)列的調(diào)用的行為。 舉一個(gè)具體的例子,假設(shè)我們要檢查REST客戶端是否正確配置為3秒鐘后超時(shí)。
為此,我們需要的是一個(gè)小型Controller ,該Controller將在返回答案到REST客戶端之前等待,以模擬REST API。 等待時(shí)間將作為參數(shù)傳遞給查詢字符串。
@Profile("restTemplateTimeout") @RestController @RequestMapping(value = "/test") public class DelayedWebServerController {@RequestMapping(value = "/delayRestTemplate", method = GET)public String answerWithDelay(@RequestParam Long waitTimeMs) {if (waitTimeMs > 0) {try {Thread.sleep(waitTimeMs);} catch (InterruptedException e) {throw new RuntimeException(e);}}return "Delayed Result";}}@Profile批注用于什么? 如果我們將此控制器注入到我們的標(biāo)準(zhǔn)應(yīng)用程序上下文中,則有幾個(gè)缺點(diǎn):
- 測試將會(huì)很慢:我們只需要啟動(dòng)一個(gè)控制器,而不是整個(gè)控制器
- 我們的控制器將由Spring拾取并注入其他所有集成測試中,從而減慢每個(gè)集成測試的速度,并可能踩到另一個(gè)測試的腳趾
更好的選擇是啟動(dòng)一個(gè)最小的Spring Boot應(yīng)用程序,僅暴露我們的DelayedWebServerController 。 我們還將告訴Spring Boot僅掃描我們感興趣的軟件包,并排除與持久性相關(guān)的自動(dòng)配置,因?yàn)槲覀儾恍枰鼇韱?dòng)控制器。 這是在類似以下的Configuration類中完成的:
@Profile("restTemplateTimeout") @Configuration @EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class}) @ComponentScan(basePackages = "my.application.resttemplate.timeout") public class DelayedWebServerConfiguration {//The class is empty and only used to support the annotations }Spring上下文配置可能會(huì)引起混亂,讓我們一個(gè)接一個(gè)地查看批注:
- @Profile :這告訴Spring,只有在restTemplateTimeout配置文件處于活動(dòng)狀態(tài)時(shí)才應(yīng)使用此配置。 在本文的進(jìn)一步內(nèi)容中,我們將看到如何為特定的集成測試啟用此配置文件。 正是這個(gè)注釋防止配置被其他不相關(guān)的集成測試所采用。 請(qǐng)注意,我們的DelayedWebServerController具有相同的注釋。
- @Configuration :標(biāo)準(zhǔn)注釋,用于告訴Spring這是一個(gè)上下文配置類。
- @EnableAutoConfiguration :在這里,我們禁用了某些不需要進(jìn)行特定測試的Spring Boot“魔術(shù)”
- @ComponentScan :通過僅掃描一個(gè)軟件包而不是整個(gè)項(xiàng)目,我們可以加快Spring Boot應(yīng)用程序的啟動(dòng)速度。 Spring不會(huì)選擇此包之外的任何帶有Spring注釋的類。
集成測試如下所示:
@RunWith(SpringJUnit4ClassRunner.class) @WebIntegrationTest("server.port:0") @SpringApplicationConfiguration(classes = DelayedWebServerConfiguration.class) @ActiveProfiles("restTemplateTimeout") public class RestTemplateShould {@Rulepublic ExpectedException thrown = none();@Value("${local.server.port}")private int port;@Autowiredprivate RestTemplate restTemplate;@Testpublic void throw_timeout_if_response_lasts_more_than_two_seconds() {thrown.expect(ResourceAccessException.class);thrown.expectCause(instanceOf(SocketTimeoutException.class));callEndpointWithDelay(3000);}@Testpublic void do_not_throw_timeout_if_response_lasts_less_than_two_seconds() {callEndpointWithDelay(10);}private void callEndpointWithDelay(long delayMs) {restTemplate.getForObject("http://localhost:" + port + "/test/delayRestTemplate?waitTimeMs=" + delayMs, String.class);} }當(dāng)然,所有這些類都存儲(chǔ)在我們的測試源文件夾(通常為src/test/java )中,因?yàn)樯a(chǎn)不需要它們。
讓我們?cè)倏匆幌伦⒔?#xff1a;
- @RunWith :測試將使用Spring Junit運(yùn)行程序,該運(yùn)行程序?qū)⒇?fù)責(zé)為我們創(chuàng)建Spring上下文。
- @WebIntegrationTest :告訴Spring這是一個(gè)運(yùn)行Web應(yīng)用程序的集成測試,否則默認(rèn)情況下Spring不會(huì)在測試模式下運(yùn)行HTTP服務(wù)器。 我們還將server.port的值設(shè)置為0以便Spring Boot選擇一個(gè)隨機(jī)端口供HTTP服務(wù)器監(jiān)聽。 這允許并行運(yùn)行多個(gè)測試,或者在后臺(tái)運(yùn)行該應(yīng)用程序的另一個(gè)版本。
- @SpringApplicationConfiguration :我們告訴Spring在哪里可以找到我們之前創(chuàng)建的DelayedWebServerConfiguration類。
- @ActiveProfiles :啟用restTemplateTimeout配置文件,否則Controller和Configuration將被過濾掉。
現(xiàn)在,我們有一個(gè)集成測試,它以一組有限的依賴關(guān)系而不是整個(gè)應(yīng)用程序運(yùn)行。 如果我們想走得更遠(yuǎn)并在游戲中添加模擬游戲怎么辦? 當(dāng)依賴項(xiàng)沒有開發(fā)環(huán)境,或者過于復(fù)雜而無法從開發(fā)人員的工作站調(diào)用時(shí),可能需要這樣做。 在這種情況下,我們可以將這些模擬添加到Configuration類中,并將它們注入到測試的Spring上下文中。
這是一個(gè)Configuration示例,在該示例中,我們注入了一個(gè)由Mockito模擬的自定義CustomerService ,而不是默認(rèn)值:
@Profile("validationTests") @Configuration @EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class}) @ComponentScan(basePackages = {"my.application.controller","my.application.actions"}) public class ValidationEndToEndConfiguration {@Beanpublic CustomerService customerService() {return Mockito.mock(CustomerService.class);} }通過這種方法,我們可以使集成測試更具彈性。 對(duì)于緩慢或不可靠的依賴關(guān)系,讓開發(fā)人員針對(duì)模擬版本運(yùn)行集成測試會(huì)更加有效。 但是,不要忘記,最終您的應(yīng)用程序?qū)⒈仨毰c實(shí)際系統(tǒng)集成,而不是與模擬系統(tǒng)集成。 因此,讓持續(xù)集成服務(wù)器至少每天都在真實(shí)系統(tǒng)上運(yùn)行測試是有意義的。
翻譯自: https://www.javacodegeeks.com/2016/02/isolating-integration-tests-mocking-dependencies-spring-boot.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的使用Spring Boot隔离集成测试和模拟依赖项的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 广电宽带与路由器用手机怎样连接广电宽带猫
- 下一篇: 路由器怎么设置视频教程路由器如何连接视频