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());  
      }  
}  
  1. 找到可能抛出异常的代码段,将它放入一个try语句内。
  2. 调用了应该抛出异常的方法以后,在try语句内写一个fail()方法来说明:“如果运行到了这里,那么说明期望的异常没有被抛出”。
  3. 添加一个catch语句以捕获期望的异常。
  4. 在catch语句内,如果需要的话,验证捕获的异常的属性与你期望的相同。
  5. 声明该测试方法会抛出异常,这可以让代码适应性更强。
    如果测试的方法抛出的异常不同于你要捕获的异常,那么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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值