TA的每日心情 | 无聊 前天 09:05 |
---|
签到天数: 1050 天 连续签到: 1 天 [LV.10]测试总司令
|
单元测试框架
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自带。
|
|