前提:pom引用 junit junit 4.12
org.springframework spring-test 4.0.5.RELEASE test org.mockito mockito-all 1.10.19 背景: 方便后台开发自测接口,去除对象之间的复杂依赖,关注代码逻辑的正确性。 原理: 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 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 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; } }