关于单元测试

单元测试其核心诉求是将一个复杂的程序进行拆解,分解为若干个独立的可控子模块来实现测试的可控性。在本节将对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测试的方法。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐