单元测试框架
mockito
1、单元测试框架:EasyMock,Mockito
2、大多 Java Mock 库如 EasyMock 或 Mockito 都是 expect-run-verify (期望-运行-验证)方式,而 Mockito 则使用更简单,更直观的方法。
3、mokito好处:
·无需昂贵的前期启动
· 拥有很好的API,几乎没有时间成本
· 可以mock接口和类
· 步骤:执行前stub,在交互中验证
· 支持andriod
初体验
1、验证交互行为
import static org.mockito.Mockito.*;
// mock creation
List mockedList = mock(List.class);
// using mock object - it does not throw any "unexpected interaction" exception
mockedList.add("one");
mockedList.clear();
// selective, explicit, highly readable verification
verify(mockedList).add("one");
verify(mockedList).clear();
一旦创建mock,就会记住所有的交互,可以自行选择需要的。
2、方法返回
// you can mock concrete classes, not only interfaces
LinkedList mockedList = mock(LinkedList.class);
// stubbing appears before the actual execution
when(mockedList.get(0)).thenReturn("first");
// the following prints "first"
System.out.println(mockedList.get(0));
// the following prints "null" because get(999) was not stubbed
System.out.println(mockedList.get(999));
mock方法返回。
3、参数匹配
//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).someMethod(anyInt(), anyString(), eq("third argument"));
//above is correct - eq() is also an argument matcher
verify(mock).someMethod(anyInt(), anyString(), "third argument");
//above is incorrect - exception will be thrown because third argument is given without an argument matcher.
4、验证确切的调用次数
//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");
默认是times(1), 所以可以显示省略times(1)
5、异常处理
doThrow(new RuntimeException()).when(mockedList).clear();
//following throws RuntimeException:
mockedList.clear();
6、验证顺序
// 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
创建InOrder对象实现,支持多个mock对象的顺序。
7、验证从未发生过调用/冗余调用
//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);
//using mocks
mockedList.add("one");
mockedList.add("two");
verify(mockedList).add("one");
//following verification will fail
verifyNoMoreInteractions(mockedList);
基本使用方法
1、基本的API
·mock()/@Mock:创建mock对象
· spy()/@Spy: 部分mock,真实的方法会被调用,依然可以被验证和stub
· @InjectMocks:自动注入mock/spy字段(@Spy或者@Mock修饰的字段)
· verify():验证指定的方法是否调用
2、mock方式:
· 注解3种方式
- @RunWith(MockitoJUnitRunner.class) 基于junit4或者
- before方法里添加 MockitoAnnotations.openMocks(this);
//目标service
@InjectMocks
private CommonService commonService;
//mock的service
@Mock
private CustomerService customerService;
@Test
public void checkLoginNameAndGetCustomer() {
//mock方法设置返回值
Mockito.when(this.customerService.findByLoginName("cnn"))
.thenAnswer((InvocationOnMock mock) -> new CustCustomer());
//测试目标方便并验证
Assert.notNull(this.commonService.checkLoginNameAndGetCustomer("cnn"), "为空");
//验证mock的方法是否有调用
Mockito.verify(this.customerService).findByLoginName("cnn");
}
- MockitoJUnit.rule()
· 非注解(略)
easyMock
初体验
@RunWith(EasyMockRunner.class)
public class ExampleTest {
//目标类
@TestSubject
private ClassUnderTest classUnderTest = new ClassUnderTest(); // 2
@Mock
private Collaborator mock; // 1
@Test
public void testRemoveNonExistingDocument() {
// ... 期望操作
replay(mock);
classUnderTest.removeDocument("Does not exist");
// ... 验证
verify()
}
}
基本使用方法
常见注解
@Mock,@TestSubject等
总结:
1、有效提高代码质量,不适合单元测试的代码不是好代码。
2、提升自测效率,不需要启动spring容器。
3、快速排除隐藏bug,弥补功能测试不到位的地方。
4、推荐使用mockito,因为springboot自带。
本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理