目录
为什么需要使用mockito
在实际项目中,当在编写单元测试时,往往遇到需要测试的类有许多依赖,而所依赖的类/对象/资源又有许多依赖,形成了一个非常复杂的依赖树。这时候就需要通过mock的方式虚拟化测试类的依赖,只测试测试类的功能。
mock依赖类1和依赖类2
mockito介绍
Mockito是用于写Java的单元测试框架,在单元测试中使用Mockito来创建和模拟(Mock)假的Java对象,进而简化外部的依赖。
mockito使用demo
1.springboot使用mockito
实体类:
package com.yantaibai.com.mockito.modal;
import lombok.Data;
@Data
public class User {
private String id;
private String name;
private int age;
}
Dao类:
package com.yantaibai.com.mockito.dao;
import com.yantaibai.com.mockito.modal.User;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface UserMapper {
List<User> getUsers();
}
被测试类:
package com.yantaibai.com.mockito.service;
import com.yantaibai.com.mockito.dao.UserMapper;
import com.yantaibai.com.mockito.modal.User;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
public class UserService implements IUserService {
@Autowired
UserMapper usermapper;
public List<User> getUser() {
return usermapper.getUsers();
}
}
测试类:
public class UserMock {
@InjectMocks
UserService userService;
@Mock
UserMapper mapper;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test
public void getUserMock(){
List<User> userList=new ArrayList();
User user=new User();
user.setId("123456789");
user.setName("aaa");
user.setAge(18);
userList.add(user);
Mockito.when(mapper.getUsers()).thenReturn(userList);
userService.getUser();
Assert.assertEquals(userService.getUser(),userList);
}
}
2.mockito常用测试demo(官网链接)
verify:检验某一行为是否发生
//Let's import Mockito statically so that the code looks clearer
import static org.mockito.Mockito.*;
//mock creation
List mockedList = mock(List.class);
//using mock object
mockedList.add("one");
mockedList.clear();
//verification
verify(mockedList).add("one");
verify(mockedList).clear();
when(mock.method()).thenReturn():带返回值方法正向测试
when(mock.method()).thenThrow():带返回值方法异向测试
//You can mock concrete classes, not just interfaces
LinkedList mockedList = mock(LinkedList.class);
//stubbing
when(mockedList.get(0)).thenReturn("first");
when(mockedList.get(1)).thenThrow(new RuntimeException());
//following prints "first"
System.out.println(mockedList.get(0));
//following throws runtime exception
System.out.println(mockedList.get(1));
//following prints "null" because get(999) was not stubbed
System.out.println(mockedList.get(999));
//Although it is possible to verify a stubbed invocation, usually it's just redundant
//If your code cares what get(0) returns, then something else breaks (often even before verify() gets executed).
//If your code doesn't care what get(0) returns, then it should not be stubbed.
verify(mockedList).get(0);
when(mock.method(anyInt)).thenReturn():带参数方法测试(入参为任何int值)
when(mock.method(argthat()).thenReturn():带参数方法测试(入参为一定的正则规则)
//stubbing using built-in anyInt() argument matcher
when(mockedList.get(anyInt())).thenReturn("element");
//stubbing using custom matcher (let's say isValid() returns your own matcher implementation):
when(mockedList.contains(argThat(isValid()))).thenReturn(true);
//following prints "element"
System.out.println(mockedList.get(999));
//you can also verify using an argument matcher
verify(mockedList).get(anyInt());
//argument matchers can also be written as Java 8 Lambdas
verify(mockedList).add(argThat(someString -> someString.length() > 5));
verify(mock,time()).method(): 检验方法调用了几次
//using mock
mockedList.add("once");
mockedList.add("twice");
mockedList.add("twice");
mockedList.add("three times");
mockedList.add("three times");
mockedList.add("three times");
//following two verifications work exactly the same - times(1) is used by default
verify(mockedList).add("once");
verify(mockedList, times(1)).add("once");
//exact number of invocations verification
verify(mockedList, times(2)).add("twice");
verify(mockedList, times(3)).add("three times");
//verification using never(). never() is an alias to times(0)
verify(mockedList, never()).add("never happened");
//verification using atLeast()/atMost()
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");
doThrow(new RuntimeException()).when(mockedList).clear():检验调用方法时抛出异常
doThrow(new RuntimeException()).when(mockedList).clear();
//following throws RuntimeException:
mockedList.clear();
verify&InOrder:判断同意方法或者不同方法的调用顺序
// A. Single mock whose methods must be invoked in a particular order
List singleMock = mock(List.class);
//using a single mock
singleMock.add("was added first");
singleMock.add("was added second");
//create an inOrder verifier for a single mock
InOrder inOrder = inOrder(singleMock);
//following will make sure that add is first called with "was added first", then with "was added second"
inOrder.verify(singleMock).add("was added first");
inOrder.verify(singleMock).add("was added second");
// B. Multiple mocks that must be used in a particular order
List firstMock = mock(List.class);
List secondMock = mock(List.class);
//using mocks
firstMock.add("was called first");
secondMock.add("was called second");
//create inOrder object passing any mocks that need to be verified in order
InOrder inOrder = inOrder(firstMock, secondMock);
//following will make sure that firstMock was called before secondMock
inOrder.verify(firstMock).add("was called first");
inOrder.verify(secondMock).add("was called second");
// Oh, and A + B can be mixed together at will
verifyzeroInteractions:检查mock方法调用0次
verifyNoMoreInteractions:检查mock方法除了verify,没有再调用
//using mocks - only mockOne is interacted
mockOne.add("one");
//ordinary verification
verify(mockOne).add("one");
//verify that method was never called on a mock
verify(mockOne, never()).add("two");
//verify that other mocks were not interacted
verifyZeroInteractions(mockTwo, mockThree);
verifyNoMoreInteractions(mockedList);
mock方法多次调用测试
//第一次返回RuntimeException(),再调用全部返回“foo”
when(mock.someMethod("some arg"))
.thenThrow(new RuntimeException())
.thenReturn("foo");
//First call: throws runtime exception:
mock.someMethod("some arg");
//Second call: prints "foo"
System.out.println(mock.someMethod("some arg"));
//Any consecutive call: prints "foo" as well (last stubbing wins).
System.out.println(mock.someMethod("some arg"));
//四次分别返回:“one”,“two”,“three”,“three”
when(mock.someMethod("some arg"))
.thenReturn("one", "two", "three");
//每次调用都返回 "two"
when(mock.someMethod("some arg"))
.thenReturn("one")
when(mock.someMethod("some arg"))
.thenReturn("two")
自定义返回格式
when(mock.someMethod(anyString())).thenAnswer(
new Answer() {
public Object answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
Object mock = invocation.getMock();
return "called with arguments: " + Arrays.toString(args);
}
});
//Following prints "called with arguments: [foo]"
System.out.println(mock.someMethod("foo"));
验证异常场景
doThrow(new RuntimeException()).when(mockedList).clear();
//following throws RuntimeException:
mockedList.clear();
调用耗时测试
//passes when someMethod() is called no later than within 100 ms
//exits immediately when verification is satisfied (e.g. may not wait full 100 ms)
verify(mock, timeout(100)).someMethod();
//above is an alias to:
verify(mock, timeout(100).times(1)).someMethod();
//passes as soon as someMethod() has been called 2 times under 100 ms
verify(mock, timeout(100).times(2)).someMethod();
//equivalent: this also passes as soon as someMethod() has been called 2 times under 100 ms
verify(mock, timeout(100).atLeast(2)).someMethod();
使用抓取器,抓取参数验证
ArgumentCaptor<String> paramCaptor=ArgumentCaptor.forClass(String.class);
Mockito.doNothing().when(mapper).getId(paramCaptor.capture());
mapper.getId("aaa");
Assert.assertEquals("aaa",paramCaptor.getValue());
使用抓取器,抓取打印的日志
public class UserMock {
@InjectMocks
UserService userService;
@Mock
UserMapper mapper;
@Mock
Appender appender;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test
public void logEvent(){
Mockito.when(appender.getName()).thenReturn("mocked");
Mockito.when(appender.isStarted()).thenReturn(true);
((Logger)LogManager.getRootLogger()).addAppender(appender);
Mockito.when(userService.getName()).thenThrow(new RuntimeException());
//创建一个抓取器
ArgumentCaptor<LogEvent> logCaptor=ArgumentCaptor.forClass(LogEvent.class);
userService.getName();
logCaptor.getAllValues().stream().filter(event->event.getMessage().equals("get the name error"))
.findFirst().orElseThrow(AssertionError::new);
}
}