Mockito可以验证
1. 值是否相等(assertEquals)
2. 方法调用几次(verify)
3. 方法调用参数是否一致(eq/ArgumentCaptor)
4. 方法调用是否按顺序
Stub
比如一个FTP程序,要测试如果断开连接是否会log错误信息Disconnected from FTP。这里断开连接是测试前提(或叫条件)是Stub,会否log错误信息是测试对象(或叫目标)。when里面只能是mock对象,不能是真实对象。when(getName(anyString(), "abc")这是不对,因为参数如果一个是matcher,其他就一定要matcher(eq, any...), i.e. eq("ewf", any())FTPClient mockedFTP = mock(FTPClient.class);
或者
@Mock
FTPClient mockedFTP
//Stub “无法连接”
when(mockedFTP.isConnected())).thenReturn(false);
when可以任意值如when(foo.add(lt(5), eq(8)))第一参数任意小于5的值及第二参数=8时返回。。
但thenReturn一定要具体指不能用any(Test.class)
//开始测试,真实调用
test.isFTPConnected();
//检查结果
assert(true, Logger.endWith("Disconnected from FTP"));
这样的测试看似显而易见,由代码一看就知道是正确,但为了确保后续维护或者refactor仍能保持这个逻辑(需求),有必要写这样的测试。
Mockito不支持连续mock,如when(mockedFTP.getConn().isConnected).thenReturn(true); 此情况可以逐个mock来做接力
@Mock Connect conn;
when(conn.isConnected).thenReturn(true);
any用于假设,any(class)用于verify
when(mockClass.get(any())).thenReturn();
verify(dynamoDao).put(any(List.class)
API:
doReturn
doNothing
doThrow
@Test(expected=ArithmeticException.class) public void testException2(){ doThrow(ArithmeticException.class).when(customer).getCustomerId(); // Act underTest.buildAnimal("tiger", 4); }
InOrder的测试:
声明mock的预期调用顺序,verify再验证
// Arrange
InOrder inOrder = inOrder(customer, myJsonHelper);
// Act
underTest.callInOrder();
// Assert
inOrder.verify(customer).setCustomerId(Mockito.anyInt());
inOrder.verify(myJsonHelper).toObject();
Verify
Mockito包括stub, verify, spy三种API。Verify是检查mock对象的某一个函数+参数这个组合(参数不同视为不同调用)的调用次数。使用场合:如果测试对象不返回结果或结果极为复杂就用此校验法。//真实调用
mockedList.add("one");
//验证add("one")这个调用是否一次
verify(mockedList).add("one");
另一个例子:
request.timestamp=1483685164
device.timestamp=1483685164
//真实调用
updateTimestampActivity.update(request);
//验证add("one")这个调用是否一次
verify(dynamoDao).put(devices);
verify(dynamoDao, times(0)).put(any(Device.class));
Main.java:
update(request){
request.timestamp=Date.now();
Devices devices = convertToObject(request);
dynamoDB.put(devices);
}
这个例子中verify对象时dynamoDao的put方法以及devices参数,由于devices在真实调用中被修改成当前时间与1483685164不一致,所以会报错:参数不一样。代码要更改成verify(dynamoDao).put(any(List.class));表示匹配任何List参数也就是不验证参数。Matchers.any(Test.class)
Matchers.anyListOf(Test.class)
参数捕捉:
public void test(){
//act
underTest.exec();
//assert
verify(math).pow(baseCaptor.capture(), exponenetCaptor.capture());
Integer base = baseCaptor.getValue();
Float exponenet = exponenetCaptor.getValue();
assertEqual(2, base);
}
@Captor
ArgumentCaptor<Integer> baseCaptor;
@Captor
ArgumentCaptor<Float> exponenetCaptor;
Math math;
@InjectMocks
Test underTest;
捕捉参数还可以用eq来代替,如verify(math).pow(eq(2), eq(1.3));等价于verify(math).pow(2,1,3)当prmitive类型时候。如果参数为复合类型,eq会调用equals去做匹配,如eq(student),而不加eq时候会比较指针。
Spy
spy是修改部分测试对象的部分API以满足测试条件,此法慎用。假设UnderTest有两个函数getProfile(), getName(),而getProfile()内部调用getName(), 此时getName若用when().thenReturn做mock会报错因为getName()也是UnderTest的一个函数。这是可以用spy来修改UnderTest的API来满足。@InjectMocks和@Spy可以连用。例如:
StudentTest:
public void test(){
//因为student是spy,所以student.get(Name)可以假设
doReturn("Gary").when(student).getName();
}
@InjectMocks
@Spy
Student student;
Mockito用于有dependency情况下测试,JUnit是无条件下测试,两者结合使用。
Annotation:
用annotation显得代码更简洁annotation | mock | 功能 |
@RunWith(MockitoJUnitRunner.class) | MockitoAnnotations.initMocks(this); | 初始化 |
@Mock | Mockito.mock(ArrayList.class) | 自动产生实例,用于假设或叫依赖。如果mock类成员一定要与@InjectMocks连用,否则时null不自动产生实例 |
@Captor | ArgumentCaptor.forClass(String.class) | 参数捕捉 |
@InjectMocks | MyDictionary dic; | 自动产生实例。需要测试的obj也叫UnderTest,而它的域成员可以mock,用来测试每个函数 |
class Student {
String name;
public void exam(Dialog dialog){}
}
StudentTest:
@Mock
String name;
@InjectMocks
Student student;
@Mock
Dialog dialog;
这里dialog是独立的,即使没有InjectMocks也不影响。但name依赖于student的存在。
另一个例子:
@Test
public void test_BuildAnimal(){
// Arrange
when(customer.getCustomerId()).thenReturn(0);
// Act
Animal animal = underTest.buildAnimal("tiger", 4);
// Assert
assertEquals("0:tiger", animal.drivedName());
}
@InjectMocks
VideoSpeechlet underTest;
@Mock
Customer customer;
Mockito有一定局限性,解决方案是PowerMock。
mock contructor:
https://lkrnac.net/blog/2014/01/mock-constructor/
EqualsBuilder
排除某些fields如id
assertTrue(EqualsBuilder.reflectionEquals(student, student2, new String[]{"id"}))
assertTrue(EqualsBuilder.reflectionEquals(student, student2, "id"))
Ref:
理论:
http://blog.csdn.net/zhangxin09/article/details/42422643
API:
http://blog.csdn.net/onlyqi/article/details/6544989
实例:
http://blog.csdn.net/onlyqi/article/details/6546589
JUnit:
http://blog.csdn.net/zhangxin09/article/details/42418441
c编程示例代码
ReplyDelete功能:排序字符串代码