差異處
這裏顯示兩個版本的差異處。
下次修改 | 前次修改 | ||
java:spring:test:springinjunithellowworld [2019/01/30 22:54] tony 建立 |
java:spring:test:springinjunithellowworld [2023/06/25 09:48] (目前版本) |
||
---|---|---|---|
行 1: | 行 1: | ||
+ | {{tag>java junit spring spring-test}} | ||
====== Spring In JUnit HelloWorld! ====== | ====== Spring In JUnit HelloWorld! ====== | ||
===== Introduction ===== | ===== Introduction ===== | ||
在寫這篇文章前,我只使用Spring Test去測試過我們的REST API。某一日,因為看到同事誤用的@ActiveProfile,讓我發現了其它不錯的Test Annotation。本篇文章分享給大家一些基本寫法。 | 在寫這篇文章前,我只使用Spring Test去測試過我們的REST API。某一日,因為看到同事誤用的@ActiveProfile,讓我發現了其它不錯的Test Annotation。本篇文章分享給大家一些基本寫法。 | ||
+ | \\ | ||
+ | \\ | ||
+ | Note. 我使用的spring-test版本是4.3.6。 | ||
===== Load & Close Spring Context ===== | ===== 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 ===== | ===== 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 ===== | ===== 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 ===== | ===== Reference ===== | ||
* [[https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html#testing|Official Document]] | * [[https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html#testing|Official Document]] | ||
* [[http://blog.jamesdbloom.com/UsingPropertySourceAndEnvironment.html|UsingPropertySourceAndEnvironment]] | * [[http://blog.jamesdbloom.com/UsingPropertySourceAndEnvironment.html|UsingPropertySourceAndEnvironment]] | ||
* [[https://www.solidsyntax.be/2013/10/22/clean-the-spring-context-between-tests/|Clean Spring Context]] | * [[https://www.solidsyntax.be/2013/10/22/clean-the-spring-context-between-tests/|Clean Spring Context]] | ||
+ | ===== ===== | ||
+ | ---- | ||
+ | \\ | ||
+ | ~~DISQUS~~ |