Mockito - java单元测试
一.简介
Mockito是mocking框架,它让你用简洁的API做测试,简单易学,可读性强并且验证语法简洁。
官网: http://mockito.org
项目源码:https://github.com/mockito/mockito
官方文档:https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/Mockito.html
PS:文中所有用例都由官方文档翻译改编而来
1. 为什么需要Mock
测试驱动的开发( TDD)要求我们先写单元测试,再写实现代码。在写单元测试的过程中,我们往往会遇到要测试的类有很多依赖,这些依赖的类/对象/资源又有别的依赖,从而形成一个大的依赖树,要在单元测试的环境中完整地构建这样的依赖,是一件很困难的事情。如下图所示:
为了测试类A,我们需要Mock B类和C类(用虚拟对象来代替)如下图所示:
2. mock和Mockito的关系
在软件开发中提及”mock”,通常理解为模拟对象。
为什么需要模拟? 在我们一开始学编程时,我们所写的对象通常都是独立的,并不依赖其他的类,也不会操作别的类。但实际上,软件中是充满依赖关系的,比如我们会基于service类写操作类,而service类又是基于数据访问类(DAO)的,依次下去,形成复杂的依赖关系。
单元测试的思路就是我们想在不涉及依赖关系的情况下测试代码。这种测试可以让你无视代码的依赖关系去测试代码的有效性。核心思想就是如果代码按设计正常工作,并且依赖关系也正常,那么他们应该会同时工作正常。
有些时候,我们代码所需要的依赖可能尚未开发完成,甚至还不存在,那如何让我们的开发进行下去呢?使用mock可以让开发进行下去,mock技术的目的和作用就是模拟一些在应用中不容易构造或者比较复杂的对象,从而把测试与测试边界以外的对象隔离开。
我们可以自己编写自定义的Mock对象实现mock技术,但是编写自定义的Mock对象需要额外的编码工作,同时也可能引入错误。现在实现mock技术的优秀开源框架有很多,Mockito就是一个优秀的用于单元测试的mock框架。Mockito已经在github上开源,详细请点击:https://github.com/mockito/mockito
除了Mockitob已被广泛使用以外,还有一些类似的框架,比如:
- EasyMock:早期比较流行的MocK测试框架。它提供对接口的模拟,能够通过录制、回放、检查三步来完成大体的测试过程,可以验证方法的调用种类、次数、顺序,可以令 Mock 对象返回指定的值或抛出指定异常
- PowerMock:这个工具是在EasyMock和Mockito上扩展出来的,目的是为了解决EasyMock和Mockito不能解决的问题,比如对static, final, private方法均不能mock。其实测试架构设计良好的代码,一般并不需要这些功能,但如果是在已有项目上增加单元测试,老代码有问题且不能改时,就不得不使用这些功能了
- JMockit:JMockit 是一个轻量级的mock框架是用以帮助开发人员编写测试程序的一组工具和API,该项目完全基于 Java 5 SE 的 java.lang.instrument 包开发,内部使用 ASM 库来修改Java的Bytecode
二、添加依赖
Mockitod 的maven依赖
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.8.47</version>
</dependency>
Mockitod 通常会结合junit使用
<dependency>
<groupId>org.junit</groupId>
<artifactId>com.springsource.org.junit</artifactId>
<version>4.8.2</version>
</dependency>
lombok 依赖,方便实现构造方法和get/set方法
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
</dependency>
< dependency>
< groupId> org.springframework.boot </ groupId>
< artifactId> spring-boot-starter-test </ artifactId>
< scope> test </ scope>
</ dependency>
在 SpringBoot 单元测试中使用 Mockito,引入spring-boot-starter-test 依赖,该依赖内就有包含了 JUnit、Mockito。
< dependency>
< groupId> org.springframework.boot </ groupId>
< artifactId> spring-boot-starter-test </ artifactId>
< scope> test </ scope>
</ dependency>
在测试类中导入Mockito类方便使用Mockito类的静态方法
import static org.mockito.Mockito.*;
三、初始化mock对象
Mocmokito底层本质是对被mock动态代理,拦截方法调用,改变方法行为,比如返回预期结果
mockito 定义的注解主要有三个:
- @Mock
- 默认不执行,有返回值的,默认返回null
- 定义了mock方法的执行mock(即虚假函数);
- @Spy
- 默认会调用真实的方法,有返回值的调用真实方法并返回真实值;
- 定义了mock方法的执行mock(即虚假函数);
- 可以verify验证
- @InjectMocks
- 用于自动注入@Spy和@Mock标注的对象,如:MyService 依赖 MyMockMapper、MySpyMapper,则会自动注入对应bean
- 创建实体对象,只能对类注解,不能注解接口
- 不支持verify验证
3.1 使用静态方法创建
Mocmokito使用cglib动态代理代理要模拟的类,调用静态方法Mockito.mock()传入类对象即可
// mock
Iterator iterator = mock(Iterator.class);
// spy
List<String> mockedList1 = spy(MyList.class);
// spy 重载
List<String> mockedList2 = spy(new MyList());
3.2 使用注解创建
使用注解创建模拟类更加简单,可读性好。
唯一需要注意的是,需要在@Before中调用MockitoAnnotations.initMocks(this);
public class ArticleManagerTest {
@Mock
private ArticleCalculator calculator;
@Spy
private ArticleDatabase database;
@Spy
@InjectMock
private UserProvider userProvider;
@Before
public void init(){
// 初始化带有mock注解的对象 @Mock,@Spy,@Captor,@InjectMocks
MockitoAnnotations.initMocks(this);
}
}
除了调用MockitoAnnotations.initMocks(this)
方法外,还可以给类加上mock启动注解来实现,更多说明详见:MockitoJUnitRunner类
@RunWith(MockitoJUnitRunner.class)
public class MockitoExample {
@Mock
HashMap<String, Integer> hashMap;
@Captor
ArgumentCaptor<String> keyCaptor;
@Captor
ArgumentCaptor<Integer> valueCaptor;
@Test
public void saveTest() {
hashMap.put("id", 100);
}
}
3.3 Spring 注解
spring 定义的注解主要有两个,@MockBean 和 @SpyBean 生成的对象受spring管理,相当于自动替换对应类型bean的注入,依赖这些bean的上层bean会自动注入 mockBean/spyBean。
@Component
public class ExampleTest {
@Autowired
private MyService myService;
@MockBean
MyMockMapper myMockMapper;
@SpyBean
MySpyMapper mySpyMapper;
@Test
public void shouldDoSomething() {
list.add(100);
}
}
3.4 mock常用方法
方法名 | 描述 |
---|---|
Mockito.mock(classToMock) | 模拟对象 |
Mockito.mock(classToMock,defaultAnswer) | 使用默认Answer模拟对象 |
Mockito.spy(Object) | 用spy监控真实对象,设置真实对象行为 |
Mockito.verify(mock) | 验证行为是否发生 |
Mockito.when(methodCall).thenReturn(value1).thenReturn(value2) | 触发时第一次返回value1,第n次都返回value2 |
Mockito.when(methodCall).thenReturn(value) | 参数匹配 |
Mockito.doReturn(toBeReturned).when(mock).[method] | 参数匹配(直接执行不判断) |
Mockito.when(methodCall).thenAnswer(answer)) | 预期回调接口生成期望值 |
Mockito.doThrow(toBeThrown).when(mock).[method] | 模拟抛出异常。 |
Mockito.doAnswer(answer).when(methodCall).[method] | 预期回调接口生成期望值(直接执行不判断) |
Mockito.doNothing().when(mock).[method] | 不做任何返回 |
Mockito.doCallRealMethod().when(mock).[method] | 调用真实的方法 |
Mockito.when(mock.[method] ).thenCallRealMethod() | |
reset(mock) | 重置mock |
四、mock 方法(预返回存根)
4.1 thenReturn
当使用任何整数值调用 mockedList 的 get 方法时,依次i返回first、last。
LinkedList mockedList = mock(LinkedList.class);
// mock方法,保存存根, Mockito.anyInt
when(mockedList.get(Mockito.anyInt)).thenReturn("first", "last");
// 第一次调用返回first
System.out.println(mockedList.get(1));
// 第二次调用返回last
System.out.println(mockedList.get(10));
限制只有当参数的数字是 3 时,才会回传字字符串 “hello” 。
LinkedList mockedList = mock(LinkedList.class);
// mock方法,保存存根, Mockito.anyInt
when(mockedList.get(3)).thenReturn("hello");
// 调用返回 hello
System.out.pringln(mockedList.get(3));
当调用 mockedList 的 add 方法时,不管传进来的 String 是什么,都回传 100。
LinkedList mockedList = mock(LinkedList.class);
// mock方法,保存存根, Mockito.anyInt
when(mockedList.add(Mockito.any(String.class)))).thenReturn(100);
// 调用返回 hello
System.out.pringln(mockedList.add("hello"));
4.2 thenThrow
模拟抛出异常
LinkedList mockedList = mock(LinkedList.class);
//保存存根, 设置异常
when(mockedList.get(1)).thenThrow(new RuntimeException());
//抛出异常
System.out.println(mockedList.get(1));
4.3 doNothing
模拟不返回
LinkedList mockedList = mock(LinkedList.class);
// get 方法不返回
Mockito.doNothing().when(mockedList).get();
五 verify 调用验证
5.1 验证调用次数
mock过的类,可以获取被调用的数据
LinkedList mockedList = mock(LinkedList.class);
//using mock, 分别调用1、2、3
mockedList.add("once");
mockedList.add("twice");
mockedList.add("twice");
mockedList.add("three times");
mockedList.add("three times");
mockedList.add("three times");
// 没有调用过任何函数
verifyZeroInteractions(mockedList);
// 没有调用过指定函数
verify(mockedList, times(0)).size();
verify(mockedList, never()).clear();
// 调用过指定函数
verify(mockedList).add("once");
verify(mockedList).add("twice");
// 调用一次
verify(mockedList, times(1)).add("once");
// 调用二次
verify(mockedList, times(2)).add("twice");
// 调用三次
verify(mockedList, times(3)).add("three times");
// 没调用过
verify(mockedList, never()).add("never happened");
// 最少和最多调用次数
verify(mockedList, atLeastOnce()).add("three times");
// 最少调用两次
verify(mockedList, atLeast(2)).add("three times");
// 最多调用次数
verify(mockedList, atMost(5)).add("three times");
5.2 调用顺序验证
List<String> mockedList = mock(MyList.class);
// 执行方法
mockedList.size();
mockedList.add("a parameter");
mockedList.clear();
// 验证调用顺序
InOrder inOrder = Mockito.inOrder(mockedList);
inOrder.verify(mockedList).size();
inOrder.verify(mockedList).add("a parameter");
inOrder.verify(mockedList).clear();
六、ArgumentCaptor 参数捕获
捕获测试期间函数被调用时传入的参数,比如测试A函数,经过一些列的计算后A调用了B,此时我们可以捕获B的入参,验证A的计算逻辑是否正确
ArgumentCaptor.getValue()
,返回最近一次参数ArgumentCaptor.getAllValues�()
,返回所有参数
我们可以使用assertEquals(expected, result)
来验证参数是否符合预期。
@Test
public void argumentCaptorTest() {
MyList myList = mock(MyList.class);
myList.setName("test");
ArgumentCaptor<String> capturedArgument = ArgumentCaptor.forClass(String.class);
Mockito.verify(myList).setName(capturedArgument.capture());
Assert.assertEquals("test", capturedArgument.getValue());
}
七. 参数模拟器
mockito还提供迭代器存根和回调存根,不常用,感兴趣可以看官方文档
如果使用参数匹配器,则所有参数都必须由匹配器提供。例如:(示例显示了验证,但对存根也是如此):
返回值 | 方法 | 描述 |
---|---|---|
static <T> T |
[**any**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#any())() |
|
匹配任何内容,包括null和varargs。 | ||
static <T> T |
[**any**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#any(java.lang.Class))([Class](https://docs.oracle.com/javase/6/docs/api/java/lang/Class.html?is-external=true)<T> type) |
|
匹配任何给定类型的对象,不包括null。 | 模拟数组 any(byte[].class),其他类型同理 | |
static boolean |
[**anyBoolean**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anyBoolean())() |
|
任何boolean 或非空 Boolean |
||
static byte |
[**anyByte**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anyByte())() |
|
任何byte 或者非空 Byte 。 |
||
static char |
[**anyChar**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anyChar())() |
|
任何char 或者非空 Character 。 |
||
static <T> [Collection](https://docs.oracle.com/javase/6/docs/api/java/util/Collection.html?is-external=true)<T> |
[**anyCollection**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anyCollection())() |
|
任何非null Collection 。 |
||
static double |
[**anyDouble**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anyDouble())() |
|
任何double 或者非空 Double 。 |
||
static float |
[**anyFloat**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anyFloat())() |
|
任何float 或者非空 Float 。 |
||
static int |
[**anyInt**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anyInt())() |
|
任何int或non-null Integer 。 |
||
static <T> [Iterable](https://docs.oracle.com/javase/6/docs/api/java/lang/Iterable.html?is-external=true)<T> |
[**anyIterable**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anyIterable())() |
|
任何非null Iterable 。 |
||
static <T> [List](https://docs.oracle.com/javase/6/docs/api/java/util/List.html?is-external=true)<T> |
[**anyList**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anyList())() |
|
任何非null List 。 |
||
static long |
[**anyLong**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anyLong())() |
|
任何long 或者非空 Long 。 |
||
static <K,V> [Map](https://docs.oracle.com/javase/6/docs/api/java/util/Map.html?is-external=true)<K,V> |
[**anyMap**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anyMap())() |
|
任何非null Map 。 |
||
static <T> T |
[**anyObject**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anyObject())() |
|
不推荐使用。 | ||
这将在Mockito 3.0中删除(仅适用于Java 8) | ||
static <T> [Set](https://docs.oracle.com/javase/6/docs/api/java/util/Set.html?is-external=true)<T> |
[**anySet**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anySet())() |
|
任何非null Set 。 |
||
static short |
[**anyShort**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anyShort())() |
|
任何short 或者非空 Short 。 |
||
static [String](https://docs.oracle.com/javase/6/docs/api/java/lang/String.html?is-external=true) |
[**anyString**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anyString())() |
|
任何非空 String |
||
static <T> T |
[**anyVararg**](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#anyVararg())() |
|
不推荐使用。 | ||
_从2.1.0开始使用 _[_any()_](https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/ArgumentMatchers.html#any()) |
||
八、使用案例
verify 验证行为是否发生
//模拟创建一个List对象
List<Integer> mock = Mockito.mock(List.class);
//调用mock对象的方法
mock.add(1);
mock.clear();
//验证方法是否执行
Mockito.verify(mock).add(1);
Mockito.verify(mock).clear();
verify 多次触发返回不同值
//mock一个Iterator类
Iterator iterator = mock(Iterator.class);
//预设当iterator调用next()时第一次返回hello,第n次都返回world
Mockito.when(iterator.next()).thenReturn("hello").thenReturn("world");
//使用mock的对象
String result = iterator.next() + " " + iterator.next() + " " + iterator.next();
//验证结果
Assert.assertEquals("hello world world",result);
doThrow 模拟抛出异常
@Test(expected = IOException.class)//期望报IO异常
public void when_thenThrow() throws IOException{
OutputStream mock = Mockito.mock(OutputStream.class);
//预设当流关闭时抛出异常
Mockito.doThrow(new IOException()).when(mock).close();
mock.close();
}
Answer 模拟对象
return只能提供固定的返回值,而answer可以提供更复杂的计算逻辑。
RETURNS_DEEP_STUBS 是创建mock对象时的备选参数之一,以下方法deepstubsTest
和deepstubsTest2
是等价的
@Test
public void deepstubsTest(){
A a = Mockito.mock(A.class,Mockito.RETURNS_DEEP_STUBS);
Mockito.when(a.getB().getName()).thenReturn("Beijing");
Assert.assertEquals("Beijing",a.getB().getName());
}
@Test
public void deepstubsTest2(){
A a=Mockito.mock(A.class);
B b=Mockito.mock(B.class);
Mockito.when(a.getB()).thenReturn(b);
Mockito.when(b.getName()).thenReturn("Beijing");
Assert.assertEquals("Beijing",a.getB().getName());
}
class A{
private B b;
public B getB(){
return b;
}
public void setB(B b){
this.b=b;
}
}
class B{
private String name;
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public String getSex(Integer sex){
if(sex==1){
return "man";
}else{
return "woman";
}
}
}
Answer 预期回调接口生成期望值
@Test
public void answerTest(){
List mockList = Mockito.mock(List.class);
//使用方法预期回调接口生成期望值(Answer结构)
Mockito.when(mockList.get(Mockito.anyInt())).thenAnswer(new CustomAnswer());
Assert.assertEquals("hello world:0",mockList.get(0));
Assert.assertEquals("hello world:999",mockList.get(999));
}
private class CustomAnswer implements Answer<String> {
@Override
public String answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
return "hello world:"+args[0];
}
}
等价于:(也可使用匿名内部类实现)
@Test
public void answer_with_callback(){
//使用Answer来生成我们我们期望的返回
Mockito.when(mockList.get(Mockito.anyInt())).thenAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
return "hello world:"+args[0];
}
});
Assert.assertEquals("hello world:0",mockList.get(0));
Assert. assertEquals("hello world:999",mockList.get(999));
}
Answer - 修改对未预设的调用返回默认期望(指定返回值)
//mock对象使用Answer来对未预设的调用返回默认期望值
List mock = Mockito.mock(List.class,new Answer() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
return 999;
}
});
//下面的get(1)没有预设,通常情况下会返回NULL,但是使用了Answer改变了默认期望值
Assert.assertEquals(999, mock.get(1));
//下面的size()没有预设,通常情况下会返回0,但是使用了Answer改变了默认期望值
Assert.assertEquals(999,mock.size());
doAnswer 预期回调接口生成期望值(直接执行)
@Test
public void testAnswer1(){
List<String> mock = Mockito.mock(List.class);
Mockito.doAnswer(new CustomAnswer()).when(mock).get(Mockito.anyInt());
Assert.assertEquals("大于三", mock.get(4));
Assert.assertEquals("小于三", mock.get(2));
}
public class CustomAnswer implements Answer<String> {
public String answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
Integer num = (Integer)args[0];
if( num>3 ){
return "大于三";
} else {
return "小于三";
}
}
}
when 参数匹配
@Test
public void with_arguments(){
B b = Mockito.mock(B.class);
//预设根据不同的参数返回不同的结果
Mockito.when(b.getSex(1)).thenReturn("男");
Mockito.when(b.getSex(2)).thenReturn("女");
Assert.assertEquals("男", b.getSex(1));
Assert.assertEquals("女", b.getSex(2));
//对于没有预设的情况会返回默认值
Assert.assertEquals(null, b.getSex(0));
}
class B{
private String name;
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public String getSex(Integer sex){
if(sex==1){
return "man";
}else{
return "woman";
}
}
}
when 匹配任意参数
Mockito.anyInt()
任何 int 值 ;Mockito.anyLong()
任何 long 值 ;Mockito.anyString()
任何 String 值 ;Mockito.any(XXX.class)
任何 XXX 类型的值 等等。
@Test
public void with_unspecified_arguments(){
List list = Mockito.mock(List.class);
//匹配任意参数
Mockito.when(list.get(Mockito.anyInt())).thenReturn(1);
Mockito.when(list.contains(Mockito.argThat(new IsValid()))).thenReturn(true);
Assert.assertEquals(1,list.get(1));
Assert.assertEquals(1,list.get(999));
Assert.assertTrue(list.contains(1));
Assert.assertTrue(!list.contains(3));
}
class IsValid extends ArgumentMatcher<List>{
@Override
public boolean matches(Object obj) {
return obj.equals(1) || obj.equals(2);
}
}
注意:使用了参数匹配,那么所有的参数都必须通过matchers来匹配
Mockito继承Matchers,anyInt()等均为Matchers方法
当传入两个参数,其中一个参数采用任意参数时,指定参数需要matchers来对比
Comparator comparator = mock(Comparator.class);
comparator.compare("nihao","hello");
//如果你使用了参数匹配,那么所有的参数都必须通过matchers来匹配
Mockito.verify(comparator).compare(Mockito.anyString(),Mockito.eq("hello"));
//下面的为无效的参数匹配使用
//verify(comparator).compare(anyString(),"hello");
when 自定义参数匹配
@Test
public void argumentMatchersTest(){
//创建mock对象
List<String> mock = mock(List.class);
//argThat(Matches<T> matcher)方法用来应用自定义的规则,可以传入任何实现Matcher接口的实现类。
Mockito.when(mock.addAll(Mockito.argThat(new IsListofTwoElements()))).thenReturn(true);
Assert.assertTrue(mock.addAll(Arrays.asList("one","two","three")));
}
class IsListofTwoElements extends ArgumentMatcher<List>
{
public boolean matches(Object list)
{
return((List)list).size()==3;
}
}
spy 监控真实对象,设置真实对象行为
@Test(expected = IndexOutOfBoundsException.class)
public void spy_on_real_objects(){
List list = new LinkedList();
List spy = Mockito.spy(list);
//下面预设的spy.get(0)会报错,因为会调用真实对象的get(0),所以会抛出越界异常
//Mockito.when(spy.get(0)).thenReturn(3);
//使用doReturn-when可以避免when-thenReturn调用真实对象api
Mockito.doReturn(999).when(spy).get(999);
//预设size()期望值
Mockito.when(spy.size()).thenReturn(100);
//调用真实对象的api
spy.add(1);
spy.add(2);
Assert.assertEquals(100,spy.size());
Assert.assertEquals(1,spy.get(0));
Assert.assertEquals(2,spy.get(1));
Assert.assertEquals(999,spy.get(999));
}
doNothing 不做任何返回
@Test
public void Test() {
A a = Mockito.mock(A.class);
//void 方法才能调用doNothing()
Mockito.doNothing().when(a).setName(Mockito.anyString());
a.setName("bb");
Assert.assertEquals("bb",a.getName());
}
class A {
private String name;
private void setName(String name){
this.name = name;
}
private String getName(){
return name;
}
}
doCallRealMethod 调用真实的方法
@Test
public void Test() {
A a = Mockito.mock(A.class);
//void 方法才能调用doNothing()
Mockito.when(a.getName()).thenReturn("bb");
Assert.assertEquals("bb",a.getName());
//等价于Mockito.when(a.getName()).thenCallRealMethod();
Mockito.doCallRealMethod().when(a).getName();
Assert.assertEquals("zhangsan",a.getName());
}
class A {
public String getName(){
return "zhangsan";
}
}
重置 mock
@Test
public void reset_mock(){
List list = mock(List.class);
Mockito. when(list.size()).thenReturn(10);
list.add(1);
Assert.assertEquals(10,list.size());
//重置mock,清除所有的互动和预设
Mockito.reset(list);
Assert.assertEquals(0,list.size());
}
@Mock
注解
public class MockitoTest {
@Mock
private List mockList;
//必须在基类中添加初始化mock的代码,否则报错mock的对象为NULL
public MockitoTest(){
MockitoAnnotations.initMocks(this);
}
@Test
public void AnnoTest() {
mockList.add(1);
Mockito.verify(mockList).add(1);
}
}
指定测试类使用运行器:MockitoJUnitRunner
@RunWith(MockitoJUnitRunner.class)
public class MockitoTest2 {
@Mock
private List mockList;
@Test
public void shorthand(){
mockList.add(1);
Mockito.verify(mockList).add(1);
}
}
参考材料
Mockito - java单元测试的更多相关文章
- Java单元测试(Junit+Mock+代码覆盖率)
微信公众号[程序员江湖] 作者黄小斜,斜杠青年,某985硕士,阿里 Java 研发工程师,于 2018 年秋招拿到 BAT 头条.网易.滴滴等 8 个大厂 offer,目前致力于分享这几年的学习经验. ...
- 原!!关于java 单元测试Junit4和Mock的一些总结
最近项目有在写java代码的单元测试,然后在思考一个问题,为什么要写单元测试??单元测试写了有什么用??百度了一圈,如下: 软件质量最简单.最有效的保证: 是目标代码最清晰.最有效的文档: 可以优化目 ...
- Java单元测试(Junit+Mock+代码覆盖率)---------转
Java单元测试(Junit+Mock+代码覆盖率) 原文见此处 单元测试是编写测试代码,用来检测特定的.明确的.细颗粒的功能.单元测试并不一定保证程序功能是正确的,更不保证整体业务是准备的. 单元测 ...
- 基于Springboot+Junit+Mockito做单元测试
前言 前面的两篇文章讨论过< 为什么要写单元测试,何时写,写多细 >和<单元测试规范>,这篇文章介绍如何使用Springboot+Junit+Mockito做单元测试,案例选取 ...
- Java单元测试技术1
另外两篇关于介绍easemock的文章:EasyMock 使用方法与原理剖析,使用 EasyMock 更轻松地进行测试 摘要:本文针对当前业软开发现状,先分析了WEB开发的技术特点和单元测试要解决的问 ...
- 转载-使用 Feed4JUnit 进行数据与代码分离的 Java 单元测试
JUnit 是被广泛应用的 Java 单元测试框架,但是它没有很好的提供参数化测试的支持,很多测试人员不得不把测试数据写在程序里或者通过其它方法实现数据与代码的分离,在后续的修改和维护上有诸多限制和不 ...
- Java单元测试工具:JUnit4(一)(二)(三)(四)
Java单元测试工具:JUnit4(一)--概述及简单例子 Java单元测试工具:JUnit4(二)--JUnit使用详解 Java单元测试工具:JUnit4(三)--JUnit详解之运行流程及常用注 ...
- Java单元测试框架 JUnit
Java单元测试框架 JUnit JUnit是一个Java语言的单元测试框架.它由Kent Beck和Erich Gamma建立,逐渐成为源于KentBeck的sUnit的xUnit家族中为最成功的一 ...
- Maven的安装配置及初次创建项目与java单元测试工具JUnit
Maven 安装 1.把maven安装包解压到某个位置 2.配置M2_HOME环境变量指向这个位置 3.在path环境变量中添加;%M2_HOME%\bin 配置镜像 国内的阿里云镜 ...
- 有效使用Mock编写java单元测试
Java单元测试对于开发人员质量保证至关重要,尤其当面对一团乱码的遗留代码时,没有高覆盖率的单元测试做保障,没人敢轻易对代码进行重构.然而单元测试的编写也不是一件容易的事情,除非使用TDD方式,否则编 ...
随机推荐
- 使用gulp.js打包layuiAdmin
安装nvm 在nvm目录下,找到settings.txt,追加以下两行加速nvm(淘宝镜像)node_mirror: https://npm.taobao.org/mirrors/node/npm_m ...
- 【译】基于XAML的跨平台框架对比分析
多年来,基于XAML的UI框架已经有了很大的发展.下面的图表是最好的说明.这些框架主要包含:支持跨平台应用的Avalonia UI, Uno Platform和 .NET MAUI.事实上,除了Ava ...
- Vue3 vite:is a JavaScript file. Did you mean to enable the 'allowJs' option?
描述 今天在vue3+vite下进行打包时,突然vscode报了一个error. 大概的意识是询问是否启用"allowJS"选项,因为该文件在程序内是指定用于编译的根文件. 提示信 ...
- WPF的前世今生
1.WPF的布局 WPF的布局分为相对定位和绝对定位两种. 绝对定位一般用Canvas 相对定位一般用Grid.StackPanel.DockPanel.WrapPanel 2.MVVM模式是什么 M ...
- 论文解读(CBL)《CNN-Based Broad Learning for Cross-Domain Emotion Classification》
Note:[ wechat:Y466551 | 付费咨询,非诚勿扰 ] 论文信息 论文标题:CNN-Based Broad Learning for Cross-Domain Emotion Clas ...
- c++算法之离散化
什么是离散化? 离散化,故离散数学,其中的"离散"就是不连续的意思.离散化可以保持原数值之间相对大小关系不变的情况下将其映射成正整数. 也就是给可能用到的数值按大小关系分配一个编号 ...
- 浅析 GlusterFS 与 JuiceFS 的架构异同
在进行分布式文件存储解决方案的选型时,GlusterFS 无疑是一个不可忽视的考虑对象.作为一款开源的软件定义分布式存储解决方案,GlusterFS 能够在单个集群中支持高达 PiB 级别的数据存储. ...
- Azure Data Factory(六)数据集类型为Dataverse的Link测试
一,引言 之前有讲过 Azure Data Factory 的 Copy Data 的操作,演示了将 Blob Storage1 的数据通过 Azure Data Factory 复制到 Blob S ...
- 【Qt6】工具提示以及调色板设置
工具提示即 Tool Tip,当用户把鼠标移动到某个UI对象上并悬停片刻,就会出现一个"短小精悍"的窗口,显示一些说明性文本.一般就是功能描述,让用户知道这个XX是干啥用的. 在 ...
- 深入探讨API调用性能优化与错误处理
随着互联网技术的不断发展,API(应用程序接口)已经成为软件系统中重要的组成部分.而优化API调用的性能以及处理错误和异常情况则是保障系统稳定性和可靠性的关键.本文将从以下几个方面来探讨如何进行性 ...