Mockito之:深度mock+不打桩都mock了啥+我想用被mock了的类的真实方法+我mock了返回为void的函数怎么办+mock的方法返回为Exception怎么办
先把两个测试类摆在这里
package com.newcrud.service.impl;
import org.springframework.stereotype.Component;
@Component
public class MyMockTwoServiceImpl {
//这个是为了验证深度mock
public Integer getTwo(Integer id){
return id;
}
}
package com.newcrud.service.impl;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
@Component
public class MyMockOneServiceImpl {
public Integer getInt(Integer id){
return id;
}
public String getString(String string){
return string;
}
public Double getDouble(Double dd){
return dd;
}
public Long getLong(Long ll){
return ll;
}
public int[] getIntShuZu(int[] a){
return a;
}
public List<Integer> getListInt(List<Integer> list){
return list;
}
public List<String> getListString(List<String> list){
return list;
}
public Map<Integer,String> getMap(Map<Integer,String> map){
return map;
}
public void getVoid(){
System.out.println("getVoid");
}
public RuntimeException getException(){
RuntimeException exception=new RuntimeException();
return exception;
}
public MyMockTwoServiceImpl getMyMockTwoService(){
MyMockTwoServiceImpl myMockTwoService=new MyMockTwoServiceImpl();
return myMockTwoService;
}
}
不打桩都mock了啥
下面这写test都是执行通过的。
总结一下:
返回值为int的mock结果为0
返回值为String的mock结果为null
返回值为double的mock结果为0.0
返回值为Long的mock结果为0L
返回值为int[]的mock结果为null
返回值为List的mock结果为[]
返回值为List的mock结果为[]
返回值为Map的mock结果为{}
package com.newcrud.service.impl;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import java.util.*;
import static org.testng.Assert.*;
@SpringBootTest
public class MyMockOneServiceImplTest extends AbstractTestNGSpringContextTests {
@BeforeClass
public void initMocks(){
MockitoAnnotations.initMocks(this);
}
@Mock
MyMockOneServiceImpl myMockOneService;
@Test
public void testGetInt() {
Integer id =myMockOneService.getInt(999);
Integer id2=0;
assertEquals(id,id2);
}
@Test
public void testGetString() {
String s=myMockOneService.getString("zhangsan");
assertEquals(s,null);
}
@Test
public void testGetDouble() {
Double dou =myMockOneService.getDouble(2.2);
assertEquals(dou,0.0);
}
@Test
public void testGetLong() {
Long lon = myMockOneService.getLong(100000L);
Long lon2 = 0L;
assertEquals(lon2,lon);
}
@Test
public void testGetIntShuZu(){
int[] a=new int[]{1,2,3};
assertEquals(null,myMockOneService.getIntShuZu(a));
}
@Test
public void testGetListInt() {
List<Integer> a=new ArrayList<Integer>();
a.add(1);
List<Integer> b=new ArrayList<Integer>();
assertEquals(b,myMockOneService.getListInt(a));
}
@Test
public void testGetListString() {
List<String> a = new ArrayList<>();
a.add("zhangsan");
List<String> b=new ArrayList<>();
assertEquals(b,myMockOneService.getListString(a));
}
@Test
public void testGetMap() {
Map<Integer,String> map=new HashMap<>();
map.put(1,"zhangsan");
Map map2=new HashMap();
assertEquals(map2,myMockOneService.getMap(map));
}
}
深度mock
我们先来演示一下问题
package com.newcrud.service.impl;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
* 现状:MyMockOneServiceImpl的getMyMockTwoService方法可以获取到一个MyMockTwoServiceImpl对象,MyMockTwoServiceImpl有一个getTwo方法
* 需求:我要mock一个MyMockOneServiceImpl,调用getMyMockTwoService生成一个MyMockTwoServiceImpl对象去执行getTwo方法
* **/
@SpringBootTest
public class MyMockOneServiceImplTest extends AbstractTestNGSpringContextTests {
@BeforeClass
public void initMocks(){
MockitoAnnotations.initMocks(this);
}
@Mock
MyMockOneServiceImpl myMockOneService;
@Test
public void testDeepMock(){
MyMockTwoServiceImpl myMockTwoService=myMockOneService.getMyMockTwoService();
Assert.assertEquals(null,myMockTwoService);
//结果:测试通过
}
@Test
public void testDeepMock2(){
MyMockTwoServiceImpl myMockTwoService=myMockOneService.getMyMockTwoService();
myMockTwoService.getTwo(8);
//结果:测试失败
}
}
testDeepMock2结果:
java.lang.NullPointerException
at com.newcrud.service.impl.MyMockOneServiceImplTest.testDeepMock2(MyMockOneServiceImplTest.java:35)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:104)
at org.testng.internal.MethodInvocationHelper$1.runTestMethod(MethodInvocationHelper.java:205)
at org.springframework.test.context.testng.AbstractTestNGSpringContextTests.run(AbstractTestNGSpringContextTests.java:184)
at org.testng.internal.MethodInvocationHelper.invokeHookable(MethodInvocationHelper.java:217)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:641)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:851)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1177)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:129)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:112)
at org.testng.TestRunner.privateRun(TestRunner.java:756)
at org.testng.TestRunner.run(TestRunner.java:610)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:387)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:382)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:340)
at org.testng.SuiteRunner.run(SuiteRunner.java:289)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1293)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1218)
at org.testng.TestNG.runSuites(TestNG.java:1133)
at org.testng.TestNG.run(TestNG.java:1104)
at com.intellij.rt.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:66)
at com.intellij.rt.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:109)
分析:通过testDeepMock我们也知道了我们mock出来的myMockOneService,执行getMyMockTwoService方法,返回的是一个null对不对,那一个null去执行getTwo方法,那一定会报空指针
改进方法1
package com.newcrud.service.impl;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import static org.mockito.Mockito.when;
/**
* 现状:MyMockOneServiceImpl的getMyMockTwoService方法可以获取到一个MyMockTwoServiceImpl对象,MyMockTwoServiceImpl有一个getTwo方法
* 需求:我要mock一个MyMockOneServiceImpl,调用getMyMockTwoService生成一个MyMockTwoServiceImpl对象去执行getTwo方法
* **/
@SpringBootTest
public class MyMockOneServiceImplTest extends AbstractTestNGSpringContextTests {
@BeforeClass
public void initMocks(){
MockitoAnnotations.initMocks(this);
}
@Mock
MyMockOneServiceImpl myMockOneService;
@Test
public void testDeepMock(){
MyMockTwoServiceImpl myMockTwoService=myMockOneService.getMyMockTwoService();
Assert.assertEquals(null,myMockTwoService);
//结果:测试通过
}
@Test
public void testDeepMock2(){
MyMockTwoServiceImpl myMockTwoService1=new MyMockTwoServiceImpl();
when(myMockOneService.getMyMockTwoService()).thenReturn(myMockTwoService1);
//MyMockTwoServiceImpl myMockTwoService=myMockOneService.getMyMockTwoService();
//myMockTwoService.getTwo(8);
myMockTwoService1.getTwo(88);
//结果:测试失败
}
}
结果:执行通过,但是还是很麻烦,这要是MyMockTwoServiceImpl还有MyMockThreeServiceImpl怎么办?
改进方法二:DeepMock
package com.newcrud.service.impl;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import static org.mockito.Mockito.when;
/**
* 现状:MyMockOneServiceImpl的getMyMockTwoService方法可以获取到一个MyMockTwoServiceImpl对象,MyMockTwoServiceImpl有一个getTwo方法
* 需求:我要mock一个MyMockOneServiceImpl,调用getMyMockTwoService生成一个MyMockTwoServiceImpl对象去执行getTwo方法
* **/
@SpringBootTest
public class MyMockOneServiceImplTest extends AbstractTestNGSpringContextTests {
@BeforeClass
public void initMocks(){
MockitoAnnotations.initMocks(this);
}
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
MyMockOneServiceImpl myMockOneService;
@Test
public void testDeepMock(){
int i=myMockOneService.getMyMockTwoService().getTwo(99);
int j=0;
MyMockTwoServiceImpl myMockTwoService=myMockOneService.getMyMockTwoService();
Assert.assertEquals(i,j);
//结果:测试通过
}
}
emmmm,看起来清爽多了
我想用被mock了的类的真实方法
被mock的类,有10个方法,我只想mock其中一个
package com.newcrud.service.impl;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.Mockito.*;
@SpringBootTest
public class MyMockOneServiceImplTest extends AbstractTestNGSpringContextTests {
@BeforeClass
public void initMocks(){
MockitoAnnotations.initMocks(this);
}
@Mock(answer = Answers.CALLS_REAL_METHODS)
MyMockOneServiceImpl myMockOneService;
@Test
public void testDoRealMethod() {
//请求的是真实的myMockOneService的方法,否则应该返回的是0
int i=myMockOneService.getInt(99);
int j=99;
Assert.assertEquals(i,j);
//打桩,不打桩应该返回的是nice
when(myMockOneService.getString(anyString())).thenReturn("hello");
String s=myMockOneService.getString("nice");
Assert.assertEquals(s,"hello");
//测试通过
}
}
被mock的类,有10个方法,我想mock其中9个,只想其中一个调用真实方法
package com.newcrud.service.impl;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.Mockito.*;
@SpringBootTest
public class MyMockOneServiceImplTest extends AbstractTestNGSpringContextTests {
@BeforeClass
public void initMocks(){
MockitoAnnotations.initMocks(this);
}
@Mock
MyMockOneServiceImpl myMockOneService;
@Test
public void testDoRealMethod() {
when(myMockOneService.getString(anyString())).thenCallRealMethod();
//这里调用的是真实的方法,输入什么返回什么
String s=myMockOneService.getString("zhangsan");
String ss="zhangsan";
Assert.assertEquals(s,ss);
//测试通过
}
@Test
public void testDoRealMethod2() {
//这里调用的就是mock的方法,应该返回的是0
Integer i = myMockOneService.getInt(99);
Integer j=0;
Assert.assertEquals(i,j);
//测试通过
}
}
我mock了返回为void的函数怎么办
返回了void,我又该怎么确定它是不是被执行了呢
package com.newcrud.service.impl;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.Mockito.*;
@SpringBootTest
public class MyMockOneServiceImplTest extends AbstractTestNGSpringContextTests {
@BeforeClass
public void initMocks(){
MockitoAnnotations.initMocks(this);
}
@Mock
MyMockOneServiceImpl myMockOneService;
@Test
public void testGetVoid() {
//注意,被mock的类在when里了,方法在when外面
doNothing().when(myMockOneService).getVoid();
myMockOneService.getVoid();
//verify(被mock的类,times(期望被执行的次数)).被打桩的方法
verify(myMockOneService,times(1)).getVoid();
//测试通过
}
}
我们再来看一下失败的时候是什么样子的
package com.newcrud.service.impl;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.Mockito.*;
@SpringBootTest
public class MyMockOneServiceImplTest extends AbstractTestNGSpringContextTests {
@BeforeClass
public void initMocks(){
MockitoAnnotations.initMocks(this);
}
@Mock
MyMockOneServiceImpl myMockOneService;
@Test
public void testGetVoid() {
//注意,被mock的类在when里了,方法在when外面
doNothing().when(myMockOneService).getVoid();
myMockOneService.getVoid();
//verify(被mock的类,times(期望被执行的次数)).被打桩的方法
verify(myMockOneService,times(2)).getVoid();
//测试通过
}
}
结果
org.mockito.exceptions.verification.TooLittleActualInvocations:
myMockOneService.getVoid();
Wanted 2 times:
-> at com.newcrud.service.impl.MyMockOneServiceImplTest.testGetVoid(MyMockOneServiceImplTest.java:30)
But was 1 time:
-> at com.newcrud.service.impl.MyMockOneServiceImplTest.testGetVoid(MyMockOneServiceImplTest.java:28)
mock的方法返回为Exception怎么办
我想要测试这个方法返回了一个Exception,但是Exception又有很多种,怎么办
期望Exception=抛出Exception
package com.newcrud.service.impl;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.Mockito.when;
@SpringBootTest
public class MyMockOneServiceImplTest extends AbstractTestNGSpringContextTests {
@BeforeClass
public void initMocks(){
MockitoAnnotations.initMocks(this);
}
@Mock
MyMockOneServiceImpl myMockOneService;
@Test(expectedExceptions = RuntimeException.class)
public void testGetException() {
when(myMockOneService.getException()).thenThrow(new RuntimeException());
myMockOneService.getException();
//测试结果:通过
}
}
期望Exception!=抛出Exception
package com.newcrud.service.impl;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.Mockito.when;
@SpringBootTest
public class MyMockOneServiceImplTest extends AbstractTestNGSpringContextTests {
@BeforeClass
public void initMocks(){
MockitoAnnotations.initMocks(this);
}
@Mock
MyMockOneServiceImpl myMockOneService;
@Test(expectedExceptions = NullPointerException.class)
public void testGetException() {
when(myMockOneService.getException()).thenThrow(new RuntimeException());
myMockOneService.getException();
//测试结果:失败
}
}
期望Exception>抛出Exception
package com.newcrud.service.impl;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.Mockito.when;
@SpringBootTest
public class MyMockOneServiceImplTest extends AbstractTestNGSpringContextTests {
@BeforeClass
public void initMocks(){
MockitoAnnotations.initMocks(this);
}
@Mock
MyMockOneServiceImpl myMockOneService;
@Test(expectedExceptions = Exception.class)
public void testGetException() {
when(myMockOneService.getException()).thenThrow(new RuntimeException());
myMockOneService.getException();
//测试结果:通过
}
}