Mockito的主要作用:
Mockito主要是为了解除类之间的依赖,隔离一些无法执行的逻辑,例如:
依赖注入隔离Native方法:
public class NativeModel {
public native boolean nativeMethod();
}
public class ModelTest {
NativeModel model;
@Before
public void setUp() throws Exception {
model = new Model();
}
@Test
public void testNativeMethod() throws Exception {
Assert.assertTrue(model.nativeMethod());
}
}
直接运行会抛出UnsatisfiedLinkError,因为Junit无法调用Native方法
所以要用mock进行依赖隔离,正确写法如下:
public class ModelTest {
NativeModel model;
@Before
public void setUp() throws Exception {
model = mock(NativeModel .class);
}
@Test
public void testNativeMethod() throws Exception {
when(model.nativeMethod()).thenReturn(true);
Assert.assertTrue(model.nativeMethod());
}
}
依赖:
dependencies {
testImplementation "org.mockito:mockito-core:2.11.0"
}
Mock的几种方式:
1.普通的Mock方式:
public class Test {
@Test
public void test() {
Model model = Mockito.mock(Mode.class); //这里Mode可以是任何一个类或接口
Assert.assertNotNull(model);
}
}
2.通过mock注解:
public class MockitoAnnotationsTest {
@Mock
Model model;
@Before
public void setup(){
MockitoAnnotations.initMocks(this);
}
@Test
public void testIsNotNull(){
assertNotNull(model);
}
}
3.使用RunWith注解:
@RunWith(MockitoJUnitRunner.class)
public class test {
@Mock
Model model;
@Test
public void test(){
Assert.assertNotNull(model);
}
}
4.通过Rule:
public class test {
@Mock
Model model;
//MockitoJUnit的evaluate方法里在开始测试前执行了MockitoAnnotations.initMocks()方法,所以无需手动执行了
@Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
@Test
public void test(){
Assert.assertNotNull(model);
}
}
Spy
和mock方法类似的还有spy方法,它的创建也与mock类似,用spy替换mock就可以
它与mock方法的区别在于spy使用了对象的真实逻辑,可以理解为spy就是new了一个对象
当然spy得到的对象也可以通过打桩替换掉真实逻辑,方便测试
打桩方法:
打桩就是屏蔽类型原本的方法,而使用自定义的简单逻辑代替实际逻辑
thenReturn(T value) 设置要返回的值
thenThrow(Throwable… throwables) 设置要抛出的异常
thenAnswer(Answer<?> answer) 对结果进行拦截
doReturn(Object toBeReturned) 提前设置要返回的值
doThrow(Throwable… toBeThrown) 提前设置要抛出的异常
doAnswer(Answer answer) 提前对结果进行拦截
doCallRealMethod() 调用某一个方法的真实实现
doNothing() 设置void方法什么也不做
@Test
public void test() {
Mockito.when(Model.isEmpty("")).thenReturn(true);
Mockito.when(Model.isEmpty(null)).thenThrow(new NullPointerException());
Mockito.when(Model.isEmpty(null)).thenAnswer(answer-> {
//获得所有参数
Object[] args = answer.getArguments();
//这里可以增加一些逻辑
system.out.print("do something");
//然后返回打桩的方法相同类型的值
return false;
});
}
spy对象的创建和mock对象是类似的,使用了spy就无需像mock一样打桩了
验证方法:
after(long millis) 在给定的时间后进行验证
timeout(long millis) 验证方法执行是否超时
atLeast(int minNumberOfInvocations) 至少进行n次验证
atMost(int maxNumberOfInvocations) 至多进行n次验证
description(String description) 验证失败时输出的内容
times(int wantedNumberOfInvocations) 验证调用方法的次数
never() 验证交互没有发生,相当于times(0)
only() 验证方法只被调用一次,相当于times(1)
例:
Mockito.verify(model, Mockito.atLeast(2)).isEmpty(""); //验证model的isEmpty("")方法至少执行了两次
Mockito.verify(model, Mockito.atMost(2)).isEmpty(""); //验证model的isEmpty("")方法至少执行了两次
Mockito.verify(model, Mockito.times(2)).isEmpty(""); //验证model的isEmpty("")方法执行了两次
Mockito.verify(model, Mockito.timeout(1000).times(2)).getAge(); //验证model的isEmpty("")方法在1s内执行了两次
参数匹配器:
作用是区分参数的类型,方便依据不同的参数类型返回不同的值
anyObject() //匹配任何对象
any(Class<T> type) //与anyObject()一样
any() //与anyObject()一样
anyBoolean() //匹配任何boolean和非空Boolean
anyByte() //匹配任何byte和非空Byte
anyCollection() //匹配任何非空Collection
anyDouble() //匹配任何double和非空Double
anyFloat() //匹配任何float和非空Float
anyInt() //匹配任何int和非空Integer
anyList() //匹配任何非空List
anyLong() //匹配任何long和非空Long
anyMap() //匹配任何非空Map
anyString() //匹配任何非空String
contains(String substring) //参数包含给定的substring字符串
argThat(ArgumentMatcher <T> matcher) //创建自定义的参数匹配模式
Mockito.when(model.isEmpty(any(String.class))).thenReturn(true); //对任何输入数据都返回true;
Mockito.when(model.isEmpty(anyString())).thenReturn(true); //同上
//自定义筛选条件,满足条件的就会返回true;
Mockito.when(model.isEmpty(argThat(arg -> arg != null))).thenReturn(true);
自动注入:
public interface Person {
String getName();
}
public class Model {
Person person;
public String getName() {
return person.getName();
}
}
测试类:
public class Test {
@InjectMocks
Model model;
@Mock
Person person;
@Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
@Test
public void test() {
Mockito.when(person.getName()).thenReturn("Tom");
//这里会自动将person注入model,这里实际返回的是person的getName方法
Assert.assertEquals(model.getName(), "Tom");
}
}
Mockito框架不足:
Mockito框架不支持mock匿名类、final类、static方法、private方法,PowerMock解决了这个问题