2018年12月7日 星期五

在單元測試時避免 CommandLineRunner 被執行

最近第一次嘗試寫基於 Spring Boot 的應用程式,使用了 CommandLineRunner 來作為應用程式的入口。寫的過程因為想要方便後面做單元測試,因此盡可能地把商業邏輯都寫在 CommandLineRunner 裡頭。不過結果最後在跑單元測試時,卻發現 SpringBootTest 啟動的程序會先執行 CommandLineRunner….囧rz。

簡單搜尋一下之後,感覺上好像是因為 Spring Boot 有個啟動設定的程序,然後一般來說會因為自動搜尋設定的關係,導致它自動搜尋到 CommandLineRunner,然後就開始執行它了 。所以該做的事情是,要在單元測試中給他一個獨特的啟動設定,並且在這個啟動設定中要求忽略 CommandLineRunner。

PS. 不過這解釋也只是感覺而已,其實因為我也還沒認真閱讀過 Spring Boot 文件,很有可能其實我猜想的解釋是錯的 XD。但動作上是可以這麼做來避免單元測試時執行 CommandLineRunner 沒錯。

具體來說,可以先在 src/test/java 中加入一個給單元測試使用的啟動設定,其中要在 ComponentScan 中指定要忽略 CommandLineRunner。

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;

@Configuration
@ComponentScan(excludeFilters = @ComponentScan.Filter(
    type = FilterType.ASSIGNABLE_TYPE, value = CommandLineRunner.class))
@EnableAutoConfiguration
public class TestApplication {
}

接著在單元測試的類別上,指定 SpringBootTest 要從剛剛建立的類別去啟動。

@SpringBootTest(classes = TestApplication.class)
@ExtendWith(SpringExtension.class)
public class MyUnitTest {
    ....
}

另外提一下,這裡用的是 JUnit 5,所以 annotation 寫法跟 JUnit 4 有些不同。

參考資料
  1. Prevent Application / CommandLineRunner classes from executing during JUnit testing

沒有留言: