Introduction
在寫這篇文章前,我只使用Spring Test去測試過我們的REST API。某一日,因為看到同事誤用的@ActiveProfile,讓我發現了其它不錯的Test Annotation。本篇文章分享給大家一些基本寫法。
Note. 我使用的spring-test版本是4.3.6。
Load & Close Spring Context
下面這段是在修改之前的Load與Close Spring Context的程式碼,會註冊兩個Config,並將我們需要的物件綁定到此TestCase物件上:
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(); }
上面冗長的程式碼,只要使用以下Annotation,就可以達到Load與Close:
@RunWith(SpringRunner.class) @ContextConfiguration(classes={ModelConfig.class, MyTest.MockConfig.class}) public class RedfishSpringConfigTest { // skip }
Runner要使用SpringRunner,而ContextConfiguration可以指定你要載入的Config class;假如你的config是xml形式,可以使用下面的寫法讓它去你的classpath找設定檔:
@ContextConfiguration("myconfig.xml")
Get Bean
在執行測試過程中,一定會需要從Spring Context中取得你需要的Bean進行測試,以下是舊的寫法:
AppController controller = springContext.getBean(AppController.class);
在透過SpringRunner執行測試案例後,你可以直接在測試案例中綁定資源,以下是@Autowired寫法:
@Autowired private AppController appController;
Environment
在你的Spring Config中,你可能會讀取properties並透過Environment去取得你要的參數;而測試中也免不了需要賦予這些參數來確認功能是否正常,以下是舊的寫法:
MockEnvironment env = new MockEnvironment(); env.setProperty("interval", String.valueOf(expectedInterval)); env.setProperty("timeout", String.valueOf(expectedTimeout)); springContext = new AnnotationConfigApplicationContext(); springContext.setEnvironment(env);
假如要將測試的MockEnvironment帶入Spring Context中,這時候就要依靠ApplicationContextInitializer:
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); } }
最後就是透過@ContextConfiguration載入這個EvnInitializer:
@ContextConfiguration(classes={ModelConfig.class, MyTest.MockConfig.class},initializers=MyTest.EvnInitializer.class)
嗯..似乎要寫更多的code。其實還有另外一個方案,就是使用@TestPropertySource去指定參數:
@TestPropertySource(properties={"interval=123","timeout=456"})
但使用@TestPropertySource,如果要串變數上去,反而可讀性就不是這麼好了。
LifeCycle of the Spring Context
在舊的寫法中,Spring Context的生命週期取決於我將Load與Close放在哪裡;而spring-text則是提供了@DirtiesContext讓你設定設定生命週期。用法如下,我指定在整個test suite執行後才清除context:
@DirtiesContext(classMode=ClassMode.AFTER_CLASS)
除了上面這個,常會使用的還有ClassMode.AFTER_EACH_TEST_METHOD。至於要用哪一種,可以好好思考,畢竟Spring的Load與Close是相當花時間的。
留言
張貼留言