java单元测试

单元测试可以使用springboot自带的单元测试依赖:

1.首先是依赖

我使用的是2.5.2版本,不同版本的mockito的初始化方法可能会有变化主要是两个:

openMocks 和initMocks看springboot版本而定,高版本都会是openMocks。

 <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
 </dependency>

2.单元测试常用的几个注解:

@Test:使用该注解标注的public void方法会表示为一个测试方法;
@Ingore:表示这个方法会被忽略执行;
@BeforeClass:表示在类中的任意public static void方法执行之前执行;
@AfterClass:表示在类中的任意public static void方法之后执行;
@Before:表示在任意使用@Test注解标注的public void方法执行之前执行;
@After:表示在任意使用@Test注解标注的public void方法执行之后执行;

3.Mock的概念:

所谓的mock就是创建一个类的虚假的对象,在测试环境中,用来替换掉真实的对象,以达到两大目的:

验证这个对象的某些方法的调用情况,调用了多少次,参数是什么等等
指定这个对象的某些方法的行为,返回特定的值,或者是执行特定的动作
使用Mock之前,需要在@Before或@BeforeClass对应的方法中添加如下,表示添加mock注解初始化。

MockitoAnnotations.initMocks(this);
一般使用mock模型的话还会用到如下几个注解:

@InjectMocks:通过创建一个实例,它可以调用真实代码的方法,其余用@Mock(或@Spy)注解创建的mock将被注入到用该实例中。
@Mock:对函数的调用均执行mock(即虚假函数),不执行真正部分。
@Spy:对函数的调用均执行真正部分。

Mockito中的Mock和Spy都可用于拦截那些尚未实现或不期望被真实调用的对象和方法,并为其设置自定义行为。二者的区别在于Mock不真实调用,Spy会真实调用。
那么概念了解完了,如何使用呢?请往下看:

4.测试用例的描述:

@Mock和@Spy使用:

外部类:TestCom的方法:

public int test(int a, int b){
 log.info("testCome.到我这了");
 return a+b;
}

被测试类:EmployeeService 方法:

@Resource
private TestCom testCom;
public int test(int a, int b){
 log.info("到我这了");
 return testCom.test(a, b);
}

测试方法:

@Mock
private TestCom testCom;
@InjectMocks
private EmployeeService employeeService;


@Before
public void init() {
 MockitoAnnotations.openMocks(this);
 System.out.println("开始测试-----------------");
}
@Test
public void test(){
 when(testCom.test(anyInt(),anyInt())).thenReturn(7);
 int test = employeeService.test(1, 1);
 log.info("计算结果:{}",test);
 Assert.assertEquals(7,test);

}

(1)这样调用的话是不会打印出:testCome.到我这了,但是会返回结果7,因为mock数据是返回的是7 最后的测试结果是 true
执行结果如下:

开始测试-----------------
2021-09-22 09:31:48.602 INFO 82620 — [ main] c.t.g.unitdemo.service.EmployeeService : 到我这了
2021-09-22 09:31:48.618 INFO 82620 — [ main] com.test.gcy.unitdemo.SuitTestTwo : 计算结果:7
测试结束-----------------

(2)如果把Mock改为Spy的话是会执行TestCom的test方法的但是还是会返回结果7,这就是mock和spy的区别。

执行结果如下:

开始测试-----------------
2021-09-22 09:35:25.604 INFO 83287 — [ main] com.test.gcy.unitdemo.service.TestCom : testCome.到我这了
2021-09-22 09:35:25.615 INFO 83287 — [ main] c.t.g.unitdemo.service.EmployeeService : 到我这了
2021-09-22 09:35:25.620 INFO 83287 — [ main] com.test.gcy.unitdemo.SuitTestTwo : 计算结果:7
测试结束-----------------

注意一点:针对打桩的时候尽量使用org.mockito.ArgumentMatchers包下的模拟参数,这样会匹配任何打桩,否则如果你打桩的传递参数是A,实际测试调用的时候是B,就会打桩失效,不会返回mock数据。

额外介绍一下从controller层做单元测试的链路:
1.使用mockmvc去跑整个链路:

被测试的controller:EmployeeController

测试类:UnitdemoApplicationTests

初始化调用上下文:

private MockMvc mockMvc;
@Autowired
private WebApplicationContext context;

@Before
public void setUp() throws Exception {
 mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
}

从接口层调用:

@Test
public void testMock() throws Exception {
 MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get("/name")
 .param("title", "demo"))
 .andExpect(MockMvcResultMatchers.status().is(HttpStatus.OK.value()))
 .andDo(print()).andReturn();
 log.info("{}",mvcResult.getResponse().getContentAsString());
}

这样调用链路会包含了controller层;

2.使用模板也可以去跑整个链路:

@Autowired
private TestRestTemplate restTemplate;

@Test
public void getName() {
 String name = restTemplate.getForObject("/name?title=1111", String.class);
 System.out.println(name + "--- " +test);
 Assert.assertNotNull(name);
}

这样也是可以调用接口层面的单元测试。

静态方法调用http的方式请求别人的接口也是可以使用mock的:
依赖:

<dependency>
 <groupId>org.powermock</groupId>
 <artifactId>powermock-module-junit4</artifactId>
 <version>2.0.2</version>
 <scope>test</scope>
</dependency>
<dependency>
 <groupId>org.powermock</groupId>
 <artifactId>powermock-api-mockito2</artifactId>
 <version>2.0.2</version>
 <scope>test</scope>
</dependency>

工具类:TestUtils:

public static String test(String body){
 log.info("body:{}",body);
 return body;
}
测试类:MockStaticMethodTest

@Test
public void Test() {
 PowerMockito.mockStatic(TestUtils.class);
 PowerMockito.when(TestUtils.test(anyString())).thenReturn("hahah");

 log.info(TestUtils.test("xxx"));
}

这个mock静态方法是和@Mock注解是一样的对于被打桩的类调用的方法是不会执行的,指挥返回mock数据。

这个有个额外的注意版本对照需要一致不然会报错版本对照如下:
版本对照

上一篇:mock server


下一篇:c# 格式化百分比