背景
系统是SpringBoot的,原来单元测试用的 Mockito,不过由于版本较低,对静态方法无法Mock,所以又引入了 PowerMock;
好长时间没动过了,现在刚好有一个项目需要写测试代码,顺便也把Mockito升升级;
现在Mockito版本已经到了 5.2.0了,不过需要Java11的支持;目前项目还使用的是Java8,因此只能使用到 Mockito4,最高版本为 4.11.0;
而且从Mockito3的某个版本开始,已经支持了 静态方法的Mock,所以可以暂时抛弃PowerMock了;
依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring-boot.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito-version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>${mockito-version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>${mockito-version}</version>
<scope>test</scope>
</dependency>
<mockito-version>4.11.0</mockito-version>
其实没必要依赖这么多artifact,也没细究,看例子这样service和http都可以进行Mock测试;
Mock整个类
ClassA,调用到 ClassB , 现在自己Mock生成一个ClassB;
@Component
public class ClassA {
@Autowired
ClassB classB;
public void printA(int value ) {
int a;
a = value + classB.getValue();
System.out.println("------------------------------------------------------");
System.out.println("ClassA : a value is " + a);
System.out.println("------------------------------------------------------");
}
}
@Component
public class ClassB {
public int getValue() {
return 10;
}
}
测试代码:
@RunWith(SpringRunner.class)
@SpringBootTest
public class SimpleTest {
@Autowired
ClassA classA;
@MockBean
ClassB classB;
@Test
public void Simple() {
when(classB.getValue()).thenReturn(5);
classA.printA(5);
}
}
如果没有Mock掉ClassB,
classA.printA(5) 的结果应该是: 5 + 10 ,结果是 15;
Mock了ClassB,classB.getValue返回从10变成了5,结果应该显示10了
Mock一些方法
有时候需要使用到原始的类,但是只对其中某些方法进行Mock:
@Component
public class ClassA {
@Autowired
ClassB classB;
public int printA(int value ) {
int a;
a = value + classB.getValue();
return a;
}
public int printB(int value ) {
int b;
b = value + classB.getValue();
return b;
}
}
正常情况下
@RunWith(SpringRunner.class)
@SpringBootTest
public class SimpleTest2 {
@Autowired
ClassA classA;
@Test
public void Simple() {
System.out.println("printA : " + classA.printA(5) );
System.out.println("printB : " + classA.printB(5) );
}
}
printA(5) 和 printB(5) 结果应该是一样的:
文章来源:https://www.toymoban.com/news/detail-701064.html
如果想Mock掉ClassA.printA, 让printA返回指定的值,那就需要对printA做处理:
在对printA函数做处理之前,首先要对 classA类进行包装:
方法1 :
@Autowired
ClassA classA;
改变成:
@SpyBean
ClassA classA;
或者:
@Autowired
ClassA classA;
@Test
public void Simple() {
classA = Mockito.spy(classA);
。。。。。。
}
然后对printA进行处理:
@Test
public void Simple() {
classA = Mockito.spy(classA);
when(classA.printA(anyInt())).thenReturn(100);
System.out.println("printA : " + classA.printA(5) );
System.out.println("printB : " + classA.printB(5) );
}
结果:
其中:
when(classA.printA(anyInt())).thenReturn(100);
也可以写成
doReturn(100).when(classA).printA(anyInt());
静态方法的Mock
现在的Mockito也可以对静态方法做Mock
Bean类:
@Component
public class ClassB {
public int getValue() {
return 10;
}
public static int getStaticInt() {
return 1;
}
}
这里ClassB,多了一个静态方法: getStaticInt
在ClassA中,使用这个静态方法:
@Component
public class ClassA {
public int invokeClassBStatic(int value ) {
return value + ClassB.getStaticInt();
}
}
正常情况下,
@SpringBootTest
@RunWith(SpringRunner.class)
public class SimpleTest3 {
@Autowired
ClassA classA;
@Test
public void Simple() {
classA.invokeClassBStatic(5);
}
}
的结果是:
现在Mock掉ClassB. getStaticInt,让它返回100,代码变成:
@SpringBootTest
@RunWith(SpringRunner.class)
public class SimpleTest3 {
@Autowired
ClassA classA;
@Test
public void Simple() {
MockedStatic<ClassB> classBMockedStatic = Mockito.mockStatic(ClassB.class);
classBMockedStatic.when(
() -> ClassB.getStaticInt()
).thenReturn(100);
System.out.println(classA.invokeClassBStatic(5));
}
}
执行结果:
对void函数进行Mock
用 doNoting().when()
用新的函数Mock掉老函数
对printA进行Mock
@RunWith(SpringRunner.class)
@SpringBootTest
public class SimpleTest4 {
@SpyBean
ClassA classA;
@Test
public void Simple() {
classA = Mockito.spy(classA);
when(classA.printA(anyInt())).thenAnswer((invocation) -> {
int p = invocation.getArgument(0);
return p * 2;
});
System.out.println("printA : " + classA.printA(5));
System.out.println("printB : " + classA.printB(5));
}
}
结果:
被Mock的对象执行原方法:
对于mock的对象,它的所有方法都会被打桩,不执行真实方法,除非使用doCallRealMethod。文章来源地址https://www.toymoban.com/news/detail-701064.html
Foo mock = mock(Foo.class);
doCallRealMethod().when(mock).someVoidMethod();
// 会执行实现方法 Foo.someVoidMethod()
mock.someVoidMethod();
调用原始方法,替换原始方法
ArgumentCaptor<Object> arg1 = ArgumentCaptor.forClass(Object.class);
ArgumentCaptor<Long> arg2 = ArgumentCaptor.forClass(Long.class);
// doNothing忽略方法调用,并把方法的2个参数进行捕获
Mockito.doNothing().when(businessService).noReturnMethod1(arg1.capture(), arg2.capture());
// 方法调用
String realArg1 = "我是参数1";
long realArg2 = 123567;
businessService.noReturnMethod1(realArg1, realArg2);
// 对捕获的参数进行断言
Assert.isTrue(realArg1.equals(arg1.getValue()), "");
Assert.isTrue(realArg2 == arg2.getValue(), "");
// void方法测试2,替换void方法
Mockito.doAnswer(invocation -> {
Object objArg = invocation.getArgument(1);
Long longArg = invocation.getArgument(0);
System.out.println(objArg + "===" + longArg);
// 对捕获的参数进行断言
Assert.isTrue(realArg1.equals(objArg), "");
Assert.isTrue(realArg2 == longArg, "");
return invocation.callRealMethod();// 需要时,这里可以回调原始方法
}).when(businessService).noReturnMethod2(ArgumentMatchers.anyLong(), ArgumentMatchers.any());
businessService.noReturnMethod2(realArg2, realArg1);
到了这里,关于Mockito升级的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!