差異處
這裏顯示兩個版本的差異處。
java:spring:test:springinjunithellowworld [2019/01/30 23:49] tony |
java:spring:test:springinjunithellowworld [2023/06/25 09:48] |
||
---|---|---|---|
行 1: | 行 1: | ||
- | {{tag>java junit spring spring-test}} | + | |
- | ====== Spring In JUnit HelloWorld! ====== | + | |
- | ===== Introduction ===== | + | |
- | 在寫這篇文章前,我只使用Spring Test去測試過我們的REST API。某一日,因為看到同事誤用的@ActiveProfile,讓我發現了其它不錯的Test Annotation。本篇文章分享給大家一些基本寫法。 | + | |
- | \\ | + | |
- | Note. 我使用的spring-test版本是4.3.6。 | + | |
- | ===== Load & Close Spring Context ===== | + | |
- | 下面這段是在修改之前的Load與Close Spring Context的程式碼,會註冊兩個Config,並將我們需要的物件綁定到此TestCase物件上: | + | |
- | <code java> | + | |
- | private AnnotationConfigApplicationContext springContext; | + | |
- | @Before | + | |
- | public void setup(){ | + | |
- | springContext = new AnnotationConfigApplicationContext(); | + | |
- | springContext.setEnvironment(env); | + | |
- | springContext.register( | + | |
- | ModelConfig.class, | + | |
- | MockConfig.class | + | |
- | ); | + | |
- | + | ||
- | springContext.refresh(); | + | |
- | + | ||
- | springContext.getAutowireCapableBeanFactory().autowireBean(this); | + | |
- | } | + | |
- | + | ||
- | @After | + | |
- | public void teardown(){ | + | |
- | springContext.close(); | + | |
- | } | + | |
- | </code> | + | |
- | 上面冗長的程式碼,只要使用以下Annotation,就可以達到Load與Close: | + | |
- | <code java> | + | |
- | @RunWith(SpringRunner.class) | + | |
- | @ContextConfiguration(classes={ModelConfig.class, MyTest.MockConfig.class}) | + | |
- | public class RedfishSpringConfigTest { | + | |
- | // skip | + | |
- | } | + | |
- | </code> | + | |
- | Runner要使用SpringRunner,而ContextConfiguration可以指定你要載入的Config class;假如你的config是xml形式,可以使用下面的寫法讓它去你的classpath找設定檔: | + | |
- | <code java> | + | |
- | @ContextConfiguration("myconfig.xml") | + | |
- | </code> | + | |
- | ===== Get Bean ===== | + | |
- | 在執行測試過程中,一定會需要從Spring Context中取得你需要的Bean進行測試,以下是舊的寫法: | + | |
- | <code java> | + | |
- | AppController controller = springContext.getBean(AppController.class); | + | |
- | </code> | + | |
- | 在透過SpringRunner執行測試案例後,你可以直接在測試案例中綁定資源,以下是@Autowired寫法: | + | |
- | <code java> | + | |
- | @Autowired | + | |
- | private AppController appController; | + | |
- | </code> | + | |
- | ===== Environment ===== | + | |
- | 在你的Spring Config中,你可能會讀取properties並透過Environment去取得你要的參數;而測試中也免不了需要賦予這些參數來確認功能是否正常,以下是舊的寫法: | + | |
- | <code java> | + | |
- | MockEnvironment env = new MockEnvironment(); | + | |
- | env.setProperty("interval", String.valueOf(expectedInterval)); | + | |
- | env.setProperty("timeout", String.valueOf(expectedTimeout)); | + | |
- | + | ||
- | springContext = new AnnotationConfigApplicationContext(); | + | |
- | springContext.setEnvironment(env); | + | |
- | </code> | + | |
- | 假如要將測試的MockEnvironment帶入Spring Context中,這時候就要依靠ApplicationContextInitializer: | + | |
- | <code java> | + | |
- | public static class EnvInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { | + | |
- | @Override | + | |
- | public void initialize(ConfigurableApplicationContext applicationContext) { | + | |
- | MockEnvironment env = new MockEnvironment(); | + | |
- | env.setProperty("interval", String.valueOf(expectedInterval)); | + | |
- | env.setProperty("timeout", String.valueOf(expectedTimeout)); | + | |
- | applicationContext.setEnvironment(env); | + | |
- | } | + | |
- | } | + | |
- | </code> | + | |
- | 最後就是透過@ContextConfiguration載入這個EvnInitializer: | + | |
- | <code java> | + | |
- | @ContextConfiguration(classes={ModelConfig.class, MyTest.MockConfig.class},initializers=MyTest.EvnInitializer.class) | + | |
- | </code> | + | |
- | 嗯..似乎要寫更多的code。其實還有另外一個方案,就是使用@TestPropertySource去指定參數: | + | |
- | <code> | + | |
- | @TestPropertySource(properties={"interval=123","timeout=456"}) | + | |
- | </code> | + | |
- | 但使用@TestPropertySource,如果要串變數上去,反而可讀性就不是這麼好了。 | + | |
- | ===== LifeCycle of the Spring Context ===== | + | |
- | 在舊的寫法中,Spring Context的生命週期取決於我將Load與Close放在哪裡;而spring-text則是提供了@DirtiesContext讓你設定設定生命週期。用法如下,我指定在整個test suite執行後才清除context: | + | |
- | <code java> | + | |
- | @DirtiesContext(classMode=ClassMode.AFTER_CLASS) | + | |
- | </code> | + | |
- | 除了上面這個,常會使用的還有ClassMode.AFTER_EACH_TEST_METHOD。至於要用哪一種,可以好好思考,畢竟Spring的Load與Close是相當花時間的。 | + | |
- | ===== Reference ===== | + | |
- | * [[https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html#testing|Official Document]] | + | |
- | * [[http://blog.jamesdbloom.com/UsingPropertySourceAndEnvironment.html|UsingPropertySourceAndEnvironment]] | + | |
- | * [[https://www.solidsyntax.be/2013/10/22/clean-the-spring-context-between-tests/|Clean Spring Context]] | + | |
- | ===== ===== | + | |
- | ---- | + | |
- | \\ | + | |
- | ~~DISQUS~~ | + |