官方资料:https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html
1、验证某些行为
以List集合为例,实际测试用原本的实例代替
//导包
import static org.mockito.Mockito.*;
//创造mock对象
List mockedList = mock(List.class);
//使用mock对象
mockedList.add("one");
mockedList.clear();
//验证
verify(mockedList).add("one");
verify(mockedList).clear();
一旦创建,mock将记住所有交互。然后你可以有选择地验证你感兴趣的交互。
2、stubbing(存根)
//mock LinkedList对象
LinkedList mockedList = mock(LinkedList.class);
//stubbing
when(mockedList.get(0)).thenReturn("first");
when(mockedList.get(1)).thenThrow(new RuntimeException());
//打印"first"
System.out.println(mockedList.get(0));
//打印异常信息
System.out.println(mockedList.get(1));
//打印null,因为get(999)没有存根
System.out.println(mockedList.get(999));
//如果您的代码不关心get(0)返回什么,那么它不应该被存根。
verify(mockedList).get(0);
注意:
- 一旦存根,该方法将始终返回一个存根值,无论调用了多少次。
3、参数匹配器
//使用内置的anyInt()参数匹配器存根
when(mockedList.get(anyInt())).thenReturn("element");
//使用自定义参数匹配器
when(mockedList.contains(argThat(isValid()))).thenReturn(true);
//打印"element"
System.out.println(mockedList.get(999));
//使用参数匹配器来验证
verify(mockedList).get(anyInt());
//Java 8 可以使用Lambda表达式来验证
verify(mockedList).add(argThat(someString -> someString.length() > 5));
自定义参数匹配器
class ListOfTwoElements implements ArgumentMatcher<List> {
public boolean matches(List list) {
return list.size() == 2;
}
public String toString() {
//printed in verification errors
return "[list of 2 elements]";
}
}
List mock = mock(List.class);
when(mock.addAll(argThat(new ListOfTwoElements()))).thenReturn(true);
mock.addAll(Arrays.asList("one", "two"));
verify(mock).addAll(argThat(new ListOfTwoElements()));
在Java 8 中可以使用Lambda表达式来代替上述实现:
verify(mock).addAll(argThat(list -> list.size() == 2));
更多的参数匹配器参考:https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/ArgumentMatchers.html
4、验证准确的调用数量/至少x次 /从不
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.LinkedList;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class PersonTest {
@Test
public void test(){
LinkedList mockedList = Mockito.mock(LinkedList.class);
mockedList.add("once");
mockedList.add("twice");
mockedList.add("twice");
mockedList.add("three times");
mockedList.add("three times");
mockedList.add("three times");
//下面的两个验证工作完全相同,times缺省情况下默认是1
verify(mockedList).add("once");
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, atMostOnce()).add("once");
verify(mockedList, atLeastOnce()).add("three times");
verify(mockedList, atLeast(2)).add("three times");
verify(mockedList, atMost(5)).add("three times");
}
}
5、使用异常stub void方法
doThrow(new RuntimeException()).when(mockedList).clear();
//抛出异常:RuntimeException:
mockedList.clear();
6、验证顺序
A. 单个mock必须按特定顺序调用其方法
List singleMock = mock(List.class);
//using a single mock
singleMock.add("was added first");
singleMock.add("was added second");
//为单个mock创建一个inOrder验证器
InOrder inOrder = inOrder(singleMock);
//下面将确保add第一次调用时使用"was added first",然后使用"was added second"
inOrder.verify(singleMock).add("was added first");
inOrder.verify(singleMock).add("was added second");
B. 多个mock必须按特定顺序使用
List firstMock = mock(List.class);
List secondMock = mock(List.class);
//使用 mocks
firstMock.add("was called first");
secondMock.add("was called second");
//创建inOrder对象,任何mocks必须按照顺序验证通过
InOrder inOrder = inOrder(firstMock, secondMock);
//follow将确保firstMock在secondMock之前被调用
inOrder.verify(firstMock).add("was called first");
inOrder.verify(secondMock).add("was called second");
7、确保交互不会发生
//使用mocks -只有mockOne是交互的
mockOne.add("one");
//普通的验证
verify(mockOne).add("one");
//验证该方法从未在mock中调用
verify(mockOne, never()).add("two");
//验证其他模拟没有交互
verifyZeroInteractions(mockTwo, mockThree);
8、发现多余的交互
mockedList.add("one");
mockedList.add("two");
verify(mockedList).add("one");
//以下验证将失败
verifyNoMoreInteractions(mockedList);
不建议在每个测试方法中使用verifyNoMoreInteractions()。verifyNoMoreInteractions()是来自交互测试工具包的一个方便的断言。只在相关的场合使用。滥用它会导致过度指定、更不容易维护的测试。
9、@Mock注释
@RunWith(MockitoJUnitRunner.StrictStubs.class)
public class ExampleTest {
@Mock
private List list;
@Test
public void shouldDoSomething() {
list.add(100);
}
}
10、存根连续调用
对同一个方法调用使用不同的返回值/异常存根。
when(mock.someMethod("some arg"))
.thenThrow(new RuntimeException())
.thenReturn("foo");
//第一次调用:抛出运行时异常:
mock.someMethod("some arg");
//第二次调用:打印"foo"
System.out.println(mock.someMethod("some arg"));
//后续任何调用都打印"foo"
System.out.println(mock.someMethod("some arg"));
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!