單元測試是項目開發中必不可少的一環,在 SpringBoot 的項目中,我們用 @SpringBootTest 注解來標注一個測試類,在測試類中注入這個接口的實現類之后對每個方法進行單獨測試。
比如下面這個示例測試類:
@SpringBootTest
public class Tests {
@Test
public void testHello() {
// ...
}
}
但是隨着項目的代碼量越來越大,你會發現測試類的啟動速度變得越來越慢,而大多數情況下只是為了測試一下某個實現類的某個方法而已,比如測試一個DAO類的persist方法。
實際上, @SpringBootTest 注解還提供了兩個參數,好好利用這兩個參數就可以讓測試類的啟動速度變得更快。
1.webEnvironment
這個屬性決定了測試類要不要啟動一個 web 環境,說白了就是要不要啟動一個 Tomcat 容器,可選的值為:
- MOCK, 啟動一個模擬的 Servlet 環境,這是默認值
- RANDOM_PORT,啟動一個 Tomcat 容器,並監聽一個隨機的端口號
- DEFINED_PORT,啟動一個 Tomcat 容器,並監聽配置文件中定義的端口(未定義則默認監聽8080)
- NONE,不啟動 Tomcat 容器
只需要通過指定 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE) 即可達到加速的效果。這時測試類啟動時就只會初始化 Spring 上下文,不再啟動 Tomcat 容器了!
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
public class Tests {
@Test
public void testHello() {
// ...
}
}
2.classes
classes 屬性用來指定運行測試類需要裝載的 class 集合,如果不指定,那么會默認裝載 @SpringBootConfiguration 注解標注的類。
提到 @SpringBootConfiguration 你可能比較陌生,其實 @SpringBootApplication 的源碼里就引入了這個注解:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
// ...
}
也就是說,如果我們不指定classes屬性,那么啟動測試類時需要加載的Bean的數量和正常啟動一次入口類(即有@SpringBootApplication注解的類)加載的 Bean 數量是一樣的。
如果你的項目中有很多個 Bean, 特別是有以下幾種時:
- 有 CommandLineRunner 的實現類
- 用 @PostConstruct 注解指定了初始化方法的類
啟動測試類的時候,就只會加載需要的 Bean 到上下文中,從而加快啟動速度。比如:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes={HelloServiceImpl.class})
public class Tests {
@Test
public void testHello() {
// ...
}
}
即使此時項目中還有另外一個 Bean 在它的初始化方法里寫了類似 Thread.sleep(10000) 等操作也不會影響,因為這個 Bean 根本就沒有被加載和初始化!