Mockito小结
mock对象
Mockito.mock(A.class) 可以返回一个mock对象。
对成员变量进行mock
1.基于public和protected的成员变量使用继承的方式
public class BaseClass{
protected TestA testA;
//......
}
使用一个类来继承这个类,然后把变量通过子类的super调用传给父类
private class ClassChild extends BaseClass{
public OneClassChild(TestA testA){
super.testA = testA;
}
}
mock代码
@Test
public void testMock(){
TestA testA = new TestA();
BaseClass baseClass = new ClassChild(testA);
//假设需要调用方法callBaseClassMethod,Return根据实际情况进行返回了
when(baseClass .callBaseClassMethod()).thenReturn(0);
//......
}
2.基于private成员变量使用反射
public class OneClass{
private TestA testA;
//......
}
mock代码
@Test
public void testMock(){
TestA testA = new TestA();
OneClass oneClass = new OneClass();
Field testAField = oneClass.getClass().getDeclaredField("testA");
testAField.setAccessible(true);
testAField.set(oneClass, testA);
//假设需要调用方法callOneClassMethod,Return根据实际情况进行返回了
when(oneClass.callOneClassMethod()).thenReturn(0);
//......
}
verify验证方法调用
当测试一个返回类型为void的方法时,我们往往是验证里面某个对象中的某些方法是否被调用。
Mockito.verify(objectToVerify).methodToVerify(arguments);//objectToVerify为被mock的对象,
//methodToVerify为对象中要被调用的方法,
//arguments为方法参数
如果想验证方法被调用了n次
Mockito.verify(objectToVerify,Mockito.times(n)).methodToVerify(arguments);
//atMost(n), atLeast(n), never() 还可以验证最多n次,最少n次,未被调用
如果并不关心方法的参数是什么,可以用 anyString,anyInt,anyLong,anyDouble,anyCollectionOf(clazz), anyList(Map, set), anyListOf(clazz) …
anyObject 表示任何对象, any(clazz) 表示任何属于clazz的对象。
doReturn和doThrow
doReturn指定返回特定值:
Mockito.when(mockObject.targetMethod(args)).thenReturn(desiredReturnValue);
或者
public Socket getCosmosSocket() throws IOException {}
Mockito.doReturn(cosmosSocket).when(cosmosServiceImpl).getCosmosSocket();
public void validateEntity(final Object object){};
doThrow()指定返回时所抛异常:
Mockito.doThrow(IllegalArgumentException.class)
.when(validationService).validateEntity(Matchers.any(AnyObjectClass.class));
doAnswer判断执行的方法和参数
public ReturnValueObject quickChange(Object1 object);
Mockito.doAnswer(new Answer() {
@Override
public ReturnValueObject answer(final InvocationOnMock invocation) throws Throwable {
final Object1 originalArgument = (invocation.getArguments())[0];//得到参数
final ReturnValueObject returnedValue = new ReturnValueObject();//自定义返回值
return returnedValue ;
}
}).when(priceChangeRequestService).quickCharge(Matchers.any(Object1.class));
doNothing
常用于返回void的方法或者对测试没有任何影响的时候
public void updateRequestActionAndApproval(final List cmItems);
Mockito.doNothing().when(pagLogService).updateRequestActionAndApproval(
Matchers.any(Object1.class));
doCallRealMethod
mock一个对象时,默认情况下不会调用对象的真实方法,mock对象的所有非void方法都将返回默认值:int、long类型方法将返回0,boolean方法将返回false,对象方法将返回null等等;而void方法将什么都不做,想要真实调用需要Mockito.doCallRealMethod() 。
spy一个对象则相反,默认情况下会调用真实方法。
测试是否抛出正确的异常
1)try…catch
public void testConstructorDiesWithNull() throws Exception{
try{
Fraction oneOverZero = new Fraction(1,0);
fail("Created fraction 1/0! That's undefined!");
}
catch(IllegalArgumentException excepted){
assertEquals("denominator",excepted.getMessage());
}
}
- 找到可能抛出异常的代码段,将它放入一个try语句内。
- 调用了应该抛出异常的方法以后,在try语句内写一个fail()方法来说明:“如果运行到了这里,那么说明期望的异常没有被抛出”。
- 添加一个catch语句以捕获期望的异常。
- 在catch语句内,如果需要的话,验证捕获的异常的属性与你期望的相同。
- 声明该测试方法会抛出异常,这可以让代码适应性更强。
如果测试的方法抛出的异常不同于你要捕获的异常,那么junit将报告一个error,这样的error一般是环境或者测试程序自身错误,而不是产品代码问题。如果产品代码抛出了一个预期之外的异常,那么一般可能是潜在的问题阻碍了测试的正常运行。
2)@Test(expected=xxx)
@Test(expected= IndexOutOfBoundsException.class)
public void empty() {
new ArrayList<Object>().get(0);
}
潜在问题就是当被标记的的测试方法中任何一个操作抛出的相应的异常,这个测试就会通过,但是这种情况可以人为避免。
3)ExpectedException Rule
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void shouldTestExceptionMessage() throws IndexOutOfBoundsException {
List<Object> list = new ArrayList<Object>();
thrown.expect(IndexOutOfBoundsException.class);
thrown.expectMessage("Index: 0, Size: 0");
list.get(0); // execution will never get past this line
.......
.......
}
PowerMock mock private、static方法,测试private方法
注意mock private方法和测试private方法是不一样的!
当需要mock final方法的时候,必须加注解@PrepareForTest和@RunWith。注解@PrepareForTest里写的类是final方法所在的类。
当需要mock静态方法的时候,必须加注解@PrepareForTest和@RunWith。注解@PrepareForTest里写的类是静态方法所在的类。
当需要mock私有方法的时候, 只是需要加注解@PrepareForTest,注解里写的类是私有方法所在的类
/*
public final class UserController {
private final UserService service;
...
}//对应下面@Mock @InjectMocks注解
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest(UserController.class)
public class LastMock {
@Mock
private UserServiceImpl serviceImpl;
@InjectMocks //创建一个实例,其余用@Mock(或@Spy)注解创建的mock将被注入到用该实例中。
private UserController controller;
/**
* mock service的保存方法
*/
@Test
public void mockSave() {
User user1 = new User();
User user2 = new User();
user1.setId("1");
user2.setId("2");
Mockito.when(serviceImpl.save(user1)).thenReturn(user2); //当调用service的save()时,mock让他返回user2
User saveUser = controller.saveUser(user1); //调用
Mockito.verify(serviceImpl,Mockito.times(1)).save(user1);//verify验证mock次数
assertEquals(user2, saveUser);//断言是否mock返回的是user2
}
/**
* mock spy public方法
* @throws Exception xx
* public String getPrivateName(String name) {
if (publicCheck()){
return "public 被mock 了";
}
if (check(name)){
return "private 被mock 了";
}
return "A_" + name;
}
public boolean publicCheck() {
return false;
}
*/
@Test
public void spy_public_method() throws Exception {
UserController spy = PowerMockito.spy(controller); //监视controller的publicCheck方法,让他返回true
Mockito.when(spy.publicCheck()).thenReturn(true);
String name = spy.getPrivateName("ljw");//执行该方法
assertEquals("public 被mock 了", name);//验证
}
/**
* mock私有方法
* @throws Exception xx
* private boolean check(String name) {
return false;
}
*/
@Test
public void spy_private_method() throws Exception {
UserController spy = PowerMockito.spy(controller);
PowerMockito.when(spy, "check", any()).thenReturn(true);//私有方法mockito不行了,需要用无所不能的PowerMock监视spy
String name = spy.getPrivateName("ljw");
assertEquals("private 被mock 了", name);
}
/**
* mock 静态方法
* public static String getStaticName(String name) {
return "A_" + name;
}
*/
@Test
public void mockStaticMethod() {
PowerMockito.mockStatic(UserController.class);//mock静态方法
when(UserController.getStaticName(any())).thenReturn("hi");
String staticName = UserController.getStaticName("ljw");//执行
assertEquals("hi", staticName);//验证
}
@Test
public void mockStaticMethod_2() {
PowerMockito.mockStatic(UserController.class);
when(UserController.getStaticName(any())).thenReturn("hi");
String staticName = controller.returnName();//通过returnName()调用,看能否被mock
assertEquals("hi", staticName);
}
/**
* 测试私有方法一
* @throws InvocationTargetException xx
* @throws IllegalAccessException xx
* private String say(String content) {
return "ljw say " + content;
}
*/
@Test
public void testPrivateMethod() throws InvocationTargetException, IllegalAccessException {
Method method = PowerMockito.method(UserController.class, "say", String.class);
Object say = method.invoke(controller, "hi");
assertEquals("ljw say hi", say);
}
/**
* 测试私有方法二
* @throws Exception xx
*/
@Test
public void testPrivateMethod_2() throws Exception {
Object say = Whitebox.invokeMethod(controller, "say", "hi");
assertEquals("ljw say hi", say);
}
}
参考链接:
https://blog.csdn.net/fenglibing/article/details/16842655
http://www.cnblogs.com/wangtj-19/p/5822369.html
https://www.cnblogs.com/harolei/p/3242131.html
https://jiangduxi.iteye.com/blog/543636
https://www.cnblogs.com/ljw-bim/p/9391770.html