Springboot 單元測試簡單介紹和啓動所有測試類的方法

最近一段時間都是在補之前的技術債,一直忙着寫業務代碼沒有注重代碼的質量,leader也在強求,所有要把單元測試搞起來了

我把單元測試分爲兩種 一個是service的單元測試,一個是controller層的單元測試接;

單元測試肯定要引入單元測試包maven依賴

<dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>RELEASE</version>
            <exclusions>
                <exclusion>
                    <artifactId>opentest4j</artifactId>
                    <groupId>org.opentest4j</groupId>
                </exclusion>
            </exclusions>
        </dependency>
 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

  

在介紹兩個單元測試之前說一說我們一般寫單元測試是不是這樣的

比如只瞭解service單元測試而且測試代碼是這樣的

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {NpmcsApplication.class})
public class ResourceServiceTest {

    @Autowired
    private ResourceService resourceService;



    @Test
    public void countTotal() {
        Map<String, Object> map = resourceService.countTotal("2019-10-21", "2019-10-25");
        System.out.printl(map);
    }
}

都是傳入條件直接輸出當然並不能說這種不能達到測試的效果,但是我們是追求完美的coder要追求性能和代碼的美觀 System.out是分非常的消耗性能的,既然是單元測試肯定要有斷言,這個應該都聽過

測試包下面有斷言的方法提供了很多

 

 

 這裏有很多的斷言方法比如上面的代代碼可以修改爲

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {NpmcsApplication.class})
public class ResourceServiceTest {

    @Autowired
    private ResourceService resourceService;



    @Test
    public void countTotal() {
        Map<String, Object> map = resourceService.countTotal("2019-10-21", "2019-10-25");
         Assert.assertNotNull(map);
 
    }
}

上面代碼重點是, 測試類加@RunWith註解, 還有加上 @SpringBootTest(classes = App.class) 註解, 這裏的 App.class 是主程序java類. 主程序java程序必須是SpringBootApplication程序, 否則測試用例會報如下錯誤:
Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=...) with your test java.lang.IllegalStateException.

@RunWith是JUnit的一個註解, 用來告訴JUnit不要使用內置的方式進行單元測試, 而應該使用指定的類做單元測試 對於Spring單元測試總是要使用 SpringRunner.class . 

@SpringBootTest 用來指定SpringBoot應用程序的入口類, 該註解默認會根據包名逐級往上找, 一直找到一個SpringBoot主程序class爲止, 然後啓動該類爲單元測試準備Spring上下文環境.  Spring單元測試並不在每個測試方法前都移動一個全新的Spring上下文, 因爲這樣做太耗費時間, 而是會緩存上下文環境. 如果某個測試方法需要重新準備Spring上下文, 需要在該方法上加 @DirtiesContext 註解. 

@Test註解: JUnit在執行每個測試方法之前, 都會爲測試類創建一個新的實例, 這樣有助於隔離各個測試方法之前的相互影響. 

接下來說一下controller測試這個有點複雜用到的MockMvc,針對API測試的一個庫

話不多說直接剛代碼

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class PressureViewContorllerTest {
    @Autowired
    private WebApplicationContext context;
    private MockMvc mockMvc;
    private MockHttpSession session;

    @Before
    public void before() throws Exception {
        mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
        session = new MockHttpSession();
        User user = new User();
        user.setName("小明");
        session.setAttribute("user", user);

    }

    @After
    public void after() throws Exception {

    }

    /**
     * Method: showPressure()
     */
    @Test
    public void testShowPressure() throws Exception {
        String json = "{\n" + "\t\"startDate\": \"2019-09-14\",\n" + "\t\"endDate\": \"2019-10-14\"\n" + "}";
        MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
        params.add("startDate", "2019-09-14");
        params.add("endDate", "2019-10-14");

        RequestBuilder request =
                MockMvcRequestBuilders.post("/pressure/pressureView").contentType(MediaType.APPLICATION_JSON)
                        .params(params);
        MvcResult mvcResult = mockMvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk()).andDo(
                MockMvcResultHandlers.print()).andReturn();

        int status = mvcResult.getResponse().getStatus();

        String content = mvcResult.getResponse().getContentAsString();
        Assert.assertTrue("正確", status == 200);
        Assert.assertFalse("錯誤", status != 200);
    }

    /**
     * Method: pressureList()
     */
    @Test
    public void testPressureList() throws Exception {
        MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
        params.add("startDate", "2019-09-14");
        params.add("endDate", "2019-10-14");
        RequestBuilder request =
                MockMvcRequestBuilders.post("/pressure/list").contentType(MediaType.APPLICATION_JSON_UTF8)
                        .params(params);
        MvcResult mvcResult = mockMvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk()).andDo(
                MockMvcResultHandlers.print()).andReturn();

        int status = mvcResult.getResponse().getStatus();
        String content = mvcResult.getResponse().getContentAsString();
        Assert.assertTrue("正確", status == 200);
        Assert.assertFalse("錯誤", status != 200);
    }




} 

代代碼講解:

首先要注入MockMvc  ,MockHttpSession ,WebApplicationContext  初始化這些對象@Before這個方法是在每個Test方法之前執行,模擬登錄因爲登錄攔截檢測是否有session信息

 mockMvc.perform() 模仿頁面調用接口 MockMvcRequestBuilders.post("/pressure/list") 這個是掉POST方法 GET直接.get(url) 

MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();

 params.add("startDate", "2019-09-14");

params.add("endDate", "2019-10-14");

這個是模擬參數 使用的是 MockMvcRequestBuilders.post("/pressure/list").contentType(MediaType.APPLICATION_JSON_UTF8) .params(params);

也可以使用

mvc.perform(MockMvcRequestBuilders.get("/manPower/countManPowerByTeam").param("startDate","2019-01-01").param("endDate","2019-12-31")).andExpect(MockMvcResultMatchers.status().isOk()).andDo(MockMvcResultHandlers.print()).andReturn();
這段代碼:
mockMvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk()).andDo(
                MockMvcResultHandlers.print()).andReturn();

期望返回status是ok 並且打印放回的結果

最後附上啓動所有的測試類方法使用的是TestSuite

/**
 * 啓動所有的測試類
 * @Author zly
 * @Date 2018/11/2 09:54
 */
@RunWith(Suite.class)
@Suite.SuiteClasses({TeamServiceTest.class,
        PressureViewContorllerTest.class,
        UserControllerTest.class,
        FlowViewControllerTest.class,
        HttpConnUtilTest.class, DemandPICControllerTest.class, DemandProtraitServiceTest.class})
public class TestSuite {

就是把所有的測試類注入進來

有寫的不好之處希望各路大佬指教 共同成長

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章