javascript
鸡肉和鸡蛋–测试前解决Spring属性
考慮一個負責進行遠程調用和獲取詳細信息的服務類:
... public class CitiesService { private final WebClient.Builder webClientBuilder; private final String baseUrl; public CitiesService( WebClient.Builder webClientBuilder, @Value ( "${cityservice.url}" ) String baseUrl) { "${cityservice.url}" ) String baseUrl) { this .webClientBuilder = webClientBuilder; this .baseUrl = baseUrl; } public Flux<City> getCities() { return this .webClientBuilder.build() .get() ....這是一個Spring Bean,它通過稱為“ cityservice.url”的屬性來解析要調用的URL。
如果我想測試此類,則在使用WebClient時一直使用的方法是使用出色的Wiremock啟動模擬服務器,并使用它來測試此類。 Wiremock模擬看起來像這樣:
private static final WireMockServer WIREMOCK_SERVER = new WireMockServer(wireMockConfig().dynamicPort()); ..... WIREMOCK_SERVER.stubFor(get(urlEqualTo( "/cities" )) .withHeader( "Accept" , equalTo( "application/json" )) .willReturn(aResponse() .withStatus( 200 ) .withHeader( "Content-Type" , "application/json" ) .withBody(resultJson)));Wiremock服務器正在一個隨機端口上啟動,并設置為響應名為“ / cities”的終結點。 這是雞肉和雞蛋問題的出處:
1. CitiesService類要求在開始測試之前設置名為“ cityservice.url”的屬性。
2. Wiremock在一個隨機端口上啟動,它響應的URL是“ http:// localhost:randomport”,并且僅在測試開始后才可用。
我可以想到三種可能的解決方案來打破這種循環依賴關系:
方法1:使用硬編碼端口
這種方法取決于在固定端口而不是動態端口上啟動Wiremock,這樣可以在啟動測試時設置屬性,如下所示:
@ExtendWith (SpringExtension. class ) @SpringBootTest (classes = CitiesServiceHardcodedPortTest.SpringConfig. class , properties = "cityservice.url= http://localhost:9876 " ) public class CitiesServiceHardcodedPortTest { private static final WireMockServer WIREMOCK_SERVER = new WireMockServer(wireMockConfig().port( 9876 ));在此,Wiremock在端口9876上啟動,并且啟動時的屬性設置為“ http:// localhost:9876 /”。
這解決了問題,但是,這不是CI服務器友好的,端口可能在運行時發生沖突,這導致測試不穩定。
方法2:不使用Spring進行測試
更好的方法是不使用這些屬性:
public class CitiesServiceDirectTest { private static final WireMockServer WIREMOCK_SERVER = new WireMockServer(wireMockConfig().dynamicPort()); private CitiesService citiesService; @BeforeEach public void beforeEachTest() { final WebClient.Builder webClientBuilder = WebClient.builder(); this .citiesService = new CitiesService(webClientBuilder, WIREMOCK_SERVER.baseUrl()); }在這里,通過在構造函數中顯式設置baseUrl來創建服務,從而避免了在測試之前設置屬性的需求。
方法3:應用程序上下文初始化器
ApplicationContextInitializer用于以編程方式初始化Spring Application Context,它可與測試一起使用,以在執行實際測試之前注入屬性。 遵循以下原則:
@ExtendWith (SpringExtension. class ) @SpringBootTest (classes = CitiesServiceSpringTest.SpringConfig. class ) @ContextConfiguration (initializers = {CitiesServiceSpringTest.PropertiesInitializer. class }) public class CitiesServiceSpringTest { private static final WireMockServer WIREMOCK_SERVER = new WireMockServer(wireMockConfig().dynamicPort()); @Autowired private CitiesService citiesService; @Test public void testGetCitiesCleanFlow() throws Exception { ... } static class PropertiesInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { @Override public void initialize(ConfigurableApplicationContext applicationContext) { TestPropertyValues.of( "cityservice.url=" + " http://localhost: " + WIREMOCK_SERVER.port() ).applyTo(applicationContext.getEnvironment()); } } }首先啟動Wiremock,然后使用初始化程序初始化Spring上下文,該初始化程序使用Wiremocks動態端口注入“ cityservice.url”屬性,這種屬性可用于連接到CityService。
結論
我個人更喜歡方法2,但是最好在測試之前創建Spring的連線和相關的bean,如果類利用了這些,那么我更喜歡方法3。應用程序上下文初始化器提供了一種解決雞和蛋問題的好方法。這些屬性需要在Spring的上下文參與之前提供。
所有代碼示例均在此處提供:
方法1:https://github.com/bijukunjummen/reactive-cities-demo/blob/master/src/test/java/samples/geo/service/CitiesServiceHardcodedPortTest.java
方法2:https://github.com/bijukunjummen/reactive-cities-demo/blob/master/src/test/java/samples/geo/service/CitiesServiceDirectTest.java 方法3:https://github.com/bijukunjummen/reactive-cities-demo/blob/master/src/test/java/samples/geo/service/CitiesServiceSpringTest.java
翻譯自: https://www.javacodegeeks.com/2019/08/chicken-egg-resolving-spring-properties-ahead-test.html
總結
以上是生活随笔為你收集整理的鸡肉和鸡蛋–测试前解决Spring属性的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 老游戏安卓版(老游戏安卓)
- 下一篇: 生产备案编号(生产备案代码)