Spring容器中的類做單元測試
SpringBoot測試步驟
- 直接在測試類上面加上如下2個註解
@RunWith(SpringRunner.class)
@SpringBootTest
就能取到spring中的容器的例項,如果配置了@Autowired那麼就自動將物件注入
在測試環境中獲取一個bean,在專案中新建User類,然後在測試模組進行測試
在src/main下新建一個例項User
@Component
public class User {
}
src/test下建立測試類測試:
@RunWith(SpringRunner.class) @SpringBootTest public class UserTest { @Autowired public ApplicationContext context; @Test public void testNotNull(){ Assert.assertNotNull(context.getBean(User.class)); } }
只在測試環境有效的bean
在src/test下新建二個類,我們發現分別使用@TestComponent和@TestConfiguration二個註解修飾,這些類只在測試環境生效
@TestComponent
public class Cat {
public void index(){
System.out.println("cat index");
}
}
@TestConfiguration public class TestBeanConfiguration { @Bean public Runnable createRunnable(){ return () -> System.out.println("=====createRunnable======="); } }
測試類:
@RunWith(SpringRunner.class) @SpringBootTest(classes = {TestBeanConfiguration.class,Cat.class}) public class TestApplication { @Autowired public ApplicationContext context; @Test public void testNotNull(){ Runnable runnable = context.getBean(Runnable.class); runnable.run(); System.out.println("--------"); Cat cat = context.getBean(Cat.class); cat.index(); } }
需要在@SpringBootTest註解的引數classes中加入引數,表示將某些類納入測試環境的容器中。
配置檔案屬性的讀取
springboot會只會讀取到src/test/resources下的配置,不會讀到正式環境下的配置檔案(跟以前1.4.*版本的不一樣,以前是優先讀取測試環境配置檔案,然後讀取正式環境的配置)
@RunWith(SpringRunner.class)
@SpringBootTest
public class EnvTest {
@Autowired
public Environment environment;
@Test
public void testValue(){
Assert.assertEquals("zhihao.miao",environment.getProperty("developer.name"));
}
}
除了在配置檔案中設定屬性,測試環境載入一些配置資訊的二種方式:
第一種使用@SpringBootTest註解,註解引數properties指定其value值,第二種使用EnvironmentTestUtils.addEnvironment方法進行設定。
@RunWith(SpringRunner.class)
@SpringBootTest(properties = {"app.version=1.0"})
public class EnvTest2 {
@Autowired
private ConfigurableEnvironment environment;
@Before
public void init(){
EnvironmentTestUtils.addEnvironment(environment,"app.admin.user=zhangsan");
}
@Test
public void testApplication(){
Assert.assertEquals("1.0",environment.getProperty("app.version"));
Assert.assertEquals("zhangsan",environment.getProperty("app.admin.user"));
}
}
Mock方式的測試
正式環境只是一個介面,並沒有實現,也並沒有納入spring容器進行管理。
public interface UserDao {
Integer createUser(String userName);
}
測試
@RunWith(SpringRunner.class)
public class UserDaoTest {
//使用MockBean是因為此時容器中沒有UserMapper這個物件
@MockBean
public UserDao userDao;
//使用BDDMockito對行為進行預測,
@Before
public void init(){
BDDMockito.given(userDao.createUser("admin")).willReturn(1);
BDDMockito.given(userDao.createUser("")).willReturn(0);
BDDMockito.given(userDao.createUser(null)).willThrow(NullPointerException.class);
}
@Test(expected=NullPointerException.class)
public void testCreateUser() {
Assert.assertEquals(Integer.valueOf(1),userDao.createUser("admin")) ;
Assert.assertEquals(Integer.valueOf(0),userDao.createUser("")) ;
Assert.assertEquals(Integer.valueOf(1),userDao.createUser(null)) ;
}
}
對controller進行測試
第一種方式:
定義一個Controller,用作測試:
@RestController
public class UserController {
private Logger logger = LoggerFactory.getLogger(getClass());
@GetMapping("/user/home")
public String home(){
logger.info("user home");
return "user home";
}
@GetMapping("/user/show")
public String show(@RequestParam("id") String id){
logger.info("book show");
return "show"+id;
}
}
使用瀏覽器訪問
http://localhost:8080/user/home
http://localhost:8080/user/show?id=100
使用測試類測試
@RunWith(SpringRunner.class)
//指定web環境,隨機埠
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class UserControllerTest {
@LocalServerPort
private int port;
//這個物件是執行在web環境的時候載入到spring容器中
@Autowired
private TestRestTemplate testRestTemplate;
@Test
public void testHome(){
String context = testRestTemplate.getForObject("/index",String.class);
Assert.assertEquals("hello world",context);
}
@Test
public void testShow(){
String context = testRestTemplate.getForObject("/index?id=1",String.class);
Assert.assertEquals("hahaha",context);
}
}
第二種方式,使用@WebMvcTest註解
@RunWith(SpringRunner.class)
@WebMvcTest(controllers = UserController.class)
public class UserControllerTest2 {
@Autowired
public MockMvc mockMvc;
@Test
public void testHome() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/index")).andExpect(MockMvcResultMatchers.status().isOk());
mockMvc.perform(MockMvcRequestBuilders.get("/index")).andExpect(MockMvcResultMatchers.status().isOk()).andExpect(MockMvcResultMatchers.content().string("user home"));
}
@Test
public void testShow() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/index").param("id", "1")).andExpect(MockMvcResultMatchers.status().isOk());
mockMvc.perform(MockMvcRequestBuilders.get("/index").param("id", "1")).andExpect(MockMvcResultMatchers.status().isOk()).andExpect(MockMvcResultMatchers.content().string("show400"));
}
}
@WebMvcTest 不需要執行在web環境下,但是,需要指定controllers,表示需要測試哪些controllers。
這種方式只測試controller,controller裡面的一些依賴,需要你自己去mock
@WebMvcTest 不會載入整個spring容器。
第三種方式
使用@SpringBootTest()與@AutoConfigureMockMvc結合,@SpringBootTest使用@SpringBootTest載入測試的spring上下文環境,@AutoConfigureMockMvc自動配置MockMvc這個類,
/**
* @SpringBootTest 不能和 @WebMvcTest 同時使用
* 如果使用MockMvc物件的話,需要另外加上@AutoConfigureMockMvc註解
*/
@RunWith(SpringRunner.class)
@SpringBootTest()
@AutoConfigureMockMvc
public class UserControllerTest3 {
@Autowired
private MockMvc mvc;
@Test
public void testHome() throws Exception {
mvc.perform(MockMvcRequestBuilders.get("/index")).andExpect(MockMvcResultMatchers.status().isOk());
mvc.perform(MockMvcRequestBuilders.get("/index")).andExpect(MockMvcResultMatchers.status().isOk()).andExpect(MockMvcResultMatchers.content().string("user home"));
}
@Test
public void testShow() throws Exception {
mvc.perform(MockMvcRequestBuilders.get("/index").param("id", "1")).andExpect(MockMvcResultMatchers.status().isOk());
mvc.perform(MockMvcRequestBuilders.get("/index").param("id", "1")).andExpect(MockMvcResultMatchers.status().isOk()).andExpect(MockMvcResultMatchers.content().string("show400"));
}
}
一個註解可以使測試類可以自動配置MockMvc這個類。