mockito 入门
- 2023-02-01 广东
本文字数:3465 字
阅读完需:约 11 分钟
前言
最近在项目中跑单元测试发现直接使用 springboot 自带的测试,一整套跑起来花费数十分钟,这是无法忍受的,考虑到功能的特殊性,想到了 Spring 测试包自带的 mockito 单元测试,所以进行初次尝试使用。
测试代码
pom 包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>4.5.1</version>
<scope>test</scope>
</dependency>
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author Steven
* @Date 2023/1/30 15:45
*/
@Service
public class OrderA {
@Autowired
private OrderC orderC;
public int print() {
System.out.println("D = "+ OrderD.getResult());
System.out.println(orderC.print(2));
System.out.println("hello world");
return -1;
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author Steven
* @Date 2023/1/30 15:46
*/
@Service
public class OrderB {
@Autowired
private OrderA order;
public boolean test() {
System.out.println("order B test()");
System.out.println("order value = " + order.print());
System.out.println("order B hello world");
return true;
}
}
import org.springframework.stereotype.Service;
/**
* @author Steven
* @Date 2023/1/30 16:43
*/
@Service
public class OrderC {
public int print(int a) {
System.out.println("hello"+ a);
return -1;
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author Steven
* @Date 2023/1/30 17:32
*/
@Component
public class OrderD {
private static OrderC orderC;
@Autowired
public OrderD(OrderC orderCa) {
System.out.println("==================");
orderC = orderCa;
}
public static int getResult(){
System.out.println("hhhhh====" + OrderE.print());
return orderC.print(3);
}
}
/**
* @author Steven
* @Date 2023/1/31 14:04
*/
public class OrderE {
public static int print() {
System.out.println("ahhahahahahhaha");
return 1111111;
}
}
主要测试类
import com.timelinecapital.web.service.order.*;
import org.checkerframework.checker.units.qual.A;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.when;
/**
* @author Steven
* @Date 2023/1/30 15:48
*/
@ContextConfiguration(classes = {OrderB.class, OrderA.class, OrderC.class, OrderD.class})
@ExtendWith(SpringExtension.class)
public class OrderTest {
@Autowired
private OrderB orderB;
@MockBean
private OrderC orderC;
@Test
public void testOrder() throws Exception {
Mockito.mockStatic(OrderE.class);
// try (MockedStatic<OrderE> orderEMockedStatic = Mockito.mockStatic(OrderE.class)) {
when(OrderE.print()).thenReturn(333);
// orderEMockedStatic.close();
// }
// when(orderA.print()).thenReturn(100);
// when(orderC.print(anyInt())).thenReturn(101);
when(orderC.print(anyInt())).thenReturn(201);
boolean res = orderB.test();
Assertions.assertTrue(res);
}
}
测试代码说明:
@ExtendWith(SpringExtension.class) 这个注解重要是继承spring的环境
@ContextConfiguration 这个注解主要
- classes属性主要是导入springbean,如果不配置需要倒入的bean会报依赖注入异常
默认情况需要手动配置相关需要注入 bean 的类否则会报错,依赖注入异常,找不到相应的 bean
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'orderB': Unsatisfied dependency expressed through field 'order'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.timelinecapital.web.service.order.OrderA' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:659)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:639)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119)
有些时间需要 mock 静态方法,单纯的使用 Mockito.mockStatic(OrderE.class);会报错,需要导入 mockito-inline 包,具体原因后续分析常见的错误异常有,这错误异常很友好都提示了如何操作:
org.mockito.exceptions.base.MockitoException:
The used MockMaker SubclassByteBuddyMockMaker does not support the creation of static mocks
Mockito's inline mock maker supports static mocks based on the Instrumentation API.
You can simply enable this mock mode, by placing the 'mockito-inline' artifact where you are currently using 'mockito-core'.
Note that Mockito's inline mock maker is not supported on Android.
总结
默认情况下需要手动配置相对应的所有需要注入的 bean,凡是你这个模块需要倒入的 bean 你都需要配置,如果你不配置注入就会报错,要么注入,要么 mock,比如 OrderB 里面依赖了 OrderA 和一个静态的 OrderD 类,OrderA bean 要么 mock 要么注入,OrderD 就不一样了因为是静态的,但是导入的时候需要注入 OrderC 所以站在 Spring 的角度,都需要注入。当然也可以一开始就 mock,当一个实例被 mock 之后他就成虚拟的了,他的依赖就不需要进行注入了。
站在项目的角度,项目越大不可能为了某个功能跑一次服务,因为服务还有其他功能,所以功能测试就成了很好的解决方案,你可以随意的 mock,返回想要的值,最大角度的覆盖所有测试,唯一的缺点是,你需要考虑所有的依赖注入。
引用
使用 Mockito 模拟 Static 静态方法 https://blog.csdn.net/qq_38646452/article/details/124943944
版权声明: 本文为 InfoQ 作者【i查拉图斯特拉如是说】的原创文章。
原文链接:【http://xie.infoq.cn/article/693bf24fa6b63ff0525640944】。文章转载请联系作者。
i查拉图斯特拉如是说
生命中任何一件事都值得全力以赴 2019-08-27 加入
码出人生
评论