zoukankan      html  css  js  c++  java
  • mockito使用心得

    前提:pom引用
    <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>4.0.5.RELEASE</version>
    <scope>test</scope>
    </dependency>
    <dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-all</artifactId>
    <version>1.10.19</version>
    </dependency>

    背景:
    方便后台开发自测接口,去除对象之间的复杂依赖,关注代码逻辑的正确性。
    原理:
    Mockito就是用Java提供的Dynamic Proxy API来实现的。

    以下是简单的小demo:
    package com.mock;

    import org.junit.runner.RunWith;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.TestExecutionListeners;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
    import org.springframework.test.context.transaction.TransactionalTestExecutionListener;

    /**
    * 所以测试类的基类
    *
    * @author tom_plus
    * @date 2017-01-02-17:20
    */
    @ContextConfiguration(locations = {"classpath:applicationContext-test.xml"})
    @RunWith(SpringJUnit4ClassRunner.class)
    @TestExecutionListeners(listeners = {DependencyInjectionTestExecutionListener.class,
    TransactionalTestExecutionListener.class})
    public class AbstractServiceIT {
    }

    package com.mock.demo;

    import com.AopTargetUtils;
    import com.mock.AbstractServiceIT;
    import com.springapp.bean.Teacher;
    import com.springapp.service.TeacherService;
    import com.springapp.service.TestService;
    import com.springapp.utils.SessionContext;
    import org.junit.Before;
    import org.junit.Test;
    import org.mockito.Mock;
    import org.mockito.MockitoAnnotations;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.util.ReflectionTestUtils;
    import org.springframework.transaction.annotation.Transactional;
    import org.testng.Assert;

    import java.util.List;

    import static org.mockito.Matchers.*;
    import static org.mockito.Mockito.*;

    /**
    * mock 使用demo
    * 一个强大的用于 Java 开发的模拟测试框架
    *
    * @author tom_plus
    * @date 2017-01-02-17:45
    */
    public class MockServiceIT extends AbstractServiceIT{
    @Mock
    SessionContext sessionContext;
    @Autowired
    private TestService testService;
    @Before
    public void befTest() {
    MockitoAnnotations.initMocks(this);
    when(sessionContext.getId()).thenReturn(3);
    try {
    ReflectionTestUtils.setField(AopTargetUtils.getTarget(testService), "sessionContext", sessionContext);
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    @Test
    @Transactional
    public void updateIT() throws Exception {
    Teacher teacher = new Teacher();
    teacher.settName("樱木花道");
    int j = testService.update2(teacher);
    System.out.println("result:"+j);
    Assert.assertEquals(j,1,"更新成功");
    }

    /**
    * 参数匹配器,一旦使用参数匹配器,则方法中必须处处使用参数匹配器
    */
    @Test
    public void argumentMatcherTest(){
    List<String> list = mock(List.class);
    when(list.get(anyInt())).thenReturn("hello","world");
    String result = list.get(0)+list.get(1);
    System.out.println(result);
    //verify 方法验证mock 对象的互动次数
    verify(list,times(2)).get(anyInt());
    verify(list,atLeast(2)).get(anyInt());
    Assert.assertEquals("helloworld", result);

    }

    /**
    * 使用异常处理void 方法
    */
    @Test
    public void stubbingForVoidMethod() {
    List<String> list = mock(List.class);
    doThrow(new RuntimeException("you are clear a list!")).when(list).clear();
    list.clear();
    }
    }
    package com;

    import org.springframework.aop.framework.AdvisedSupport;
    import org.springframework.aop.framework.AopProxy;
    import org.springframework.aop.support.AopUtils;

    import java.lang.reflect.Field;

    /**
    * Created by tom_plus on 2017/1/2.
    */
    public class AopTargetUtils {
    /**
    * 获取 目标对象
    *
    * @param proxy 代理对象
    * @throws Exception 默认spring中Service对象是代理对象,不能直接把值设置到属性上,所以我们自己写个小的工具类
    */
    public static Object getTarget(Object proxy) throws Exception {
    if (!AopUtils.isAopProxy(proxy)) {
    return proxy;//不是代理对象
    }
    //jdk
    if (AopUtils.isJdkDynamicProxy(proxy)) {
    return getJdkDynamicProxyTargetObject(proxy);
    } else { //cglib
    return getCglibProxyTargetObject(proxy);
    }
    }

    private static Object getCglibProxyTargetObject(Object proxy) throws Exception {
    Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0");//获得字节码文件中的MethodInterceptor cglib$CALLBACK_0 变量
    h.setAccessible(true);
    Object dynamicAdvisedInterceptor = h.get(proxy);
    Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
    advised.setAccessible(true);
    Object target = ((AdvisedSupport) advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();
    return target;
    }


    private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception {
    Field h = proxy.getClass().getSuperclass().getDeclaredField("h");
    h.setAccessible(true);
    AopProxy aopProxy = (AopProxy) h.get(proxy);
    Field advised = aopProxy.getClass().getDeclaredField("advised");
    advised.setAccessible(true);
    Object target = ((AdvisedSupport) advised.get(aopProxy)).getTargetSource().getTarget();
    return target;
    }
    }


  • 相关阅读:
    nginx 配置文件详解
    nginx的location匹配规则
    mysql常用函数
    jquery封装的ajax请求
    docker
    in与exists和not in 与 not exists的区别
    mysql授权
    线程池
    springboot+rediscluster
    常用网址
  • 原文地址:https://www.cnblogs.com/tom-plus/p/6246725.html
Copyright © 2011-2022 走看看