Spring Boot之單元測試用例總結

bladestone發表於2019-03-27

關於單元測試

單元測試其核心訴求是將一個複雜的程式進行拆解,分解為若干個獨立的可控子模組來實現測試的可控性。在本節將對Spring Boot中可用的單元測試註解以及用法做一個小結。

通用註解

  • @RunWith(SpringRunner.class/SpringJUnit4ClassRunner.class)
    使用在測試用例類之上,用來表示當前測試用例需要使用Spring Bean容器進行執行。
    上述2個class作用相同。SpringRunner繼承於SpringJUnit4ClassRunner,為其簡寫模式。
  • @Test(expected=Exception.class, timeout=xxx)
    用來標識單個測試用例,expected表示其需要丟擲的異常,timeout表示其邏輯執行的超時時間。

程式碼示例:

import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringRunner;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;
@RunWith(SpringRunner.class) 
@Slf4j
public class UnitDemoTest {
    @Test
    public void testCase1() {
        log.info("run a single test case");
        assertThat("value is not expected", "value", equalTo("value"));
    }
}

在上述示例中,展示了一個基本的單元測試所需的內容,assertThat這個是屬於junit類庫的方法,equalTo是屬於hamcrest測試類庫的方法。在測試用例中,需要基於這幾個方法的組合來共同形成一個可用的測試用例。

Controller單元測試

  • @WebMvcTest
    專門用於測試Controller層的測試註解
  • @MockBean
    用於mockBean實際中使用的例項,其中方法的執行結果需要使用when/given等方法進行提前設定

首先定義相應的Controller類

@RestController
@Slf4j
public class HomeController {
    @GetMapping(value="/home",produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
    public String home(@RequestParam(value = "name", required = false) String name) {
        return "hello world," + name;
    }
}

單元測試示例:

@RunWith(SpringRunner.class)
@WebMvcTest(controllers = HomeController.class)
public class HomeControllerUnitTest {
    @Autowired
    private MockMvc mockMvc;

    @Test
    public void testHome() throws Exception{
        mockMvc.perform(get("/home?name={name}", "zhangsan").contentType(MediaType.TEXT_PLAIN_VALUE))
                .andExpect(status().isOk())
                .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON))
                .andExpect(content().string("hello world,zhangsan"));
    }
}

在這個簡單的Web層單元測試中,使用JUnit/Hamcrest等多個類庫的資訊。這裡並沒有體現依賴類的問題,比如如果依賴一個Service會如何來處理。
如果在Controller中依賴了一個Service例項,該如何處理呢?
首先定義一個Service類:

@RunWith(SpringRunner.class)
@WebMvcTest(controllers = HomeController.class)
public class HomeControllerUnitTest {
    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private GameService gameService;

    private String name = "Great";

    @Before
    public void setUp() {
        name = "Great";
        given(gameService.doit(name)).willReturn("play Great game");
    }

    @Test
    public void testHome() throws Exception{
        mockMvc.perform(get("/home?name={name}", name).contentType(MediaType.TEXT_PLAIN_VALUE))
                .andExpect(status().isOk())
                .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON))
                .andExpect(content().string("play Great game"));
    }
}

在這裡通過Hamcrest中的given給MockBean中的例項進行賦值操作,指定其反饋的值內容。

總結

這裡主要介紹了基於Controller的單元測試方法。在後續內容中將逐步介紹基於Service、DAO和IntegrationTest測試的方法。

相關文章