spring中使用mockito

1 mockito介绍和入门

官方:https://github.com/mockito/mockito

入门:

5分钟了解Mockito http://liuzhijun.iteye.com/blog/1512780

Mockito:一个强大的用于 Java 开发的模拟测试框架 http://www.oschina.net/translate/mockito-a-great-mock-framework-for-java-development

2 spring中正常使用mockito

上demo代码:

 1 @RunWith(SpringJUnit4ClassRunner.class)
 2 @ContextConfiguration(locations = { "classpath:testApplicationContext.xml" })
 3 public class SpringMockitoTest {
 4  
 5     @Mock
 6     private ApiService mockApiService;
 7  
 8     @Before
 9     public void initMocks() {
10         MockitoAnnotations.initMocks(this);
11         when(mockApiService.test()).thenReturn("ok");
12     }
13  
14     @Test
15     public void should_success_when_testApiService() {
16         String result = mockApiService.test();
17         Assert.assertEquals("ok", result);
18     }
19 }
20  
21 @Component
22 public class ApiService {
23  
24     @Autowired
25     private TestApiService testApiService;
26  
27     public String test() {
28         String connect = testApiService.connect();
29         connect += "test";//test自己的业务
30         return connect;
31     }
32 }
33  
34 @Component
35 public class TestApiService {
36     public String connect() {
37         return "error";
38     }
39  
40     public String  findFromDb() {
41         return "db_data";
42     }
43 }

正常使用spring和mockito中,我们把需要的mock的ApiService给mock掉,但是我们更想的是把TestApiService中的connect方法mock掉,这样就可以测试我们自己的代码,也就是ApiService中test方法自己的业务。

3 spring中mock任何容器内对象

上面的demo中,我们如何mock掉TestApiService中的test方法?

因为TestApiService是spring容器管理的bean,并且ApiService中使用到TestApiService,所以我们把ApiService中引用的TestApiService替换成我们的mock对象即可。

Spring框架有个反射工具ReflectionTestUtils,可以把一个对象中属性设置为新值,我们可以使用:

ReflectionTestUtils.setField(apiService, "testApiService", spyTestApiService);

把我们mock的testApiService放到apiService中,这样apiService调用就是我们mock的对象了;但是默认spring中apiService对象是代理对象,不能直接把值设置到属性上,所以我们自己写个小的工具类,在最后如下:

ReflectionTestUtils.setField(AopTargetUtils.getTarget(apiService), "testApiService", spyTestApiService);

完整demo:

 1 @RunWith(SpringJUnit4ClassRunner.class)
 2 @ContextConfiguration(locations = { "classpath:testApplicationContext.xml" })
 3 public class SpringMockitoTest {
 4  
 5     @Autowired
 6     private ApiService apiService;
 7     @Mock
 8     private TestApiService spyTestApiService;
 9     @Autowired
10     private TestApiService testApiService;
11  
12     @Before
13     public void initMocks() throws Exception {
14         MockitoAnnotations.initMocks(this);
15         ReflectionTestUtils.setField(AopTargetUtils.getTarget(apiService), "testApiService", spyTestApiService);
16         when(spyTestApiService.connect()).thenReturn("ok");
17     }
18  
19     @After
20     public void clearMocks() throws Exception {
21         ReflectionTestUtils.setField(AopTargetUtils.getTarget(apiService), "testApiService", testApiService);
22     }
23  
24     @Test
25     public void should_success_when_testApiService() {
26         String result = apiService.test();
27         Assert.assertEquals("oktest", result);
28     }
29 }
30  
31 @Component
32 public class ApiService {
33  
34     @Autowired
35     private TestApiService testApiService;
36  
37     public String test() {
38         String connect = testApiService.connect();
39         connect += "test";//test自己的业务
40         return connect;
41     }
42 }
43  
44 @Component
45 public class TestApiService {
46     public String connect() {
47         return "error";
48     }
49  
50     public String  findFromDb() {
51         return "db_data";
52     }
53 }
54  
55 public class AopTargetUtils {
56     /**
57      * 获取 目标对象
58      * @param proxy 代理对象
59      * @return 
60      * @throws Exception
61      */
62     public static Object getTarget(Object proxy) throws Exception { 
63         if(!AopUtils.isAopProxy(proxy)) { 
64             return proxy;//不是代理对象 
65         } 
66         if(AopUtils.isJdkDynamicProxy(proxy)) { 
67             return getJdkDynamicProxyTargetObject(proxy); 
68         } else { //cglib 
69             return getCglibProxyTargetObject(proxy); 
70         } 
71     } 
72  
73     private static Object getCglibProxyTargetObject(Object proxy) throws Exception { 
74         Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0"); 
75         h.setAccessible(true); 
76         Object dynamicAdvisedInterceptor = h.get(proxy); 
77         Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised"); 
78         advised.setAccessible(true); 
79         Object target = ((AdvisedSupport)advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget(); 
80         return target; 
81     } 
82  
83  
84     private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception { 
85         Field h = proxy.getClass().getSuperclass().getDeclaredField("h"); 
86         h.setAccessible(true); 
87         AopProxy aopProxy = (AopProxy) h.get(proxy); 
88         Field advised = aopProxy.getClass().getDeclaredField("advised"); 
89         advised.setAccessible(true); 
90         Object target = ((AdvisedSupport)advised.get(aopProxy)).getTargetSource().getTarget(); 
91         return target; 
92     } 
93 }

最后就是注意测试之后要还原现场,把spring对象还原,尤其在跑maven test的时候,否则可能会影响其他人的测试。

时间: 2024-10-08 01:54:44

spring中使用mockito的相关文章

Spring Boot项目中使用Mockito

本文首发于个人网站:Spring Boot项目中使用Mockito Spring Boot可以和大部分流行的测试框架协同工作:通过Spring JUnit创建单元测试:生成测试数据初始化数据库用于测试:Spring Boot可以跟BDD(Behavier Driven Development)工具.Cucumber和Spock协同工作,对应用程序进行测试. 进行软件开发的时候,我们会写很多代码,不过,再过六个月(甚至一年以上)你知道自己的代码怎么运作么?通过测试(单元测试.集成测试.接口测试)可

Spring中@Async用法总结

 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,其实,在spring 3.x之后,就已经内置了@Async来完美解决这个问题,本文将完成介绍@Async的用法. 1.  何为异步调用? 在解释异步调用之前,我们先来看同步调用的定义:同步就是整个处理过程顺序执行,当各个过程都执行完毕,并返回结果. 异步调用则是只是发送了调用的指令,调用者无需等待被调用的方法完全执行完毕:而是继续

(转)Spring中@Async用法总结

 原文:http://blog.csdn.net/blueheart20/article/details/44648667 引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,其实,在Spring 3.x之后,就已经内置了@Async来完美解决这个问题,本文将完成介绍@Async的用法. 1.  何为异步调用? 在解释异步调用之前,我们先来看同步调用的定义:同步就是整个处理过

Spring中@Transactional事务回滚实例及源码

一.使用场景举例 在了解@Transactional怎么用之前我们必须要先知道@Transactional有什么用.下面举个栗子:比如一个部门里面有很多成员,这两者分别保存在部门表和成员表里面,在删除某个部门的时候,假设我们默认删除对应的成员.但是在执行的时候可能会出现这种情况,我们先删除部门,再删除成员,但是部门删除成功了,删除成员的时候出异常了.这时候我们希望如果成员删除失败了,之前删除的部门也取消删除.这种场景就可以使用@Transactional事物回滚. 二.checked异常和unc

【spring教程之四】spring中bean的作用域

1. <bean id="stage" class="com.test.pro.Stage"> 在spring中,bean默认都是单例的,也就是说,spring容易只会实例化一次,在以后的每次调用中,都会使用同一个实例.下面的例子可以说明: 2.测试类 package com.test.pro; import org.springframework.context.ApplicationContext; import org.springframewor

spring中依赖注入方式总结

Spring中依赖注入的四种方式 在Spring容器中为一个bean配置依赖注入有三种方式: · 使用属性的setter方法注入  这是最常用的方式: · 使用构造器注入: · 使用Filed注入(用于注解方式). 使用属性的setter方法注入 首先要配置被注入的bean,在该bean对应的类中,应该有要注入的对象属性或者基本数据类型的属性.例如:为UserBiz类注入UserDAO,同时为UserBiz注入基本数据类型String,那么这时,就要为UserDAO对象和String类型设置se

spring中使用parent属性来减少配置

在基于spring框架开发的项目中,如果有多个bean都是一个类的实力,如配置多个数据源时,大部分配置的属性都一样,只有少部分不一样,经常是copy上一个的定义,然后修改不一样的地方.其实spring bean定义也可以和对象一样进行继承. 示例如下:  <bean id="testBeanParent"  abstract="true"  class="com.wanzheng90.bean.TestBean">         &

Spring中@Resource、@controller注解的含义

@Resource 注解被用来激活一个命名资源(named resource)的依赖注入,在JavaEE应用程序中,该注解被典型地转换为绑定于JNDI context中的一个对象. Spring确实支持使用@Resource通过JNDI lookup来解析对象,默认地,拥有与@Resource注解所提供名字相匹配的"bean name(bean名字)"的Spring管理对象会被注入. 在下面的例子中,Spring会向加了注解的setter方法传递bean名为"dataSour

spring中的aop注解(整合junit测试)

使用spring中的aop前先来了解一下spring中aop中的一些名词 Joimpoint(连接点):目标对象中,所有可能增强的方法 PointCut(切入点):目标对象,已经增强的方法 Advice(通知/增强):增强的代码 Target(目标对象):被代理对象 Weaving(织入):将通知应用到切入点的过程 Proxy(代理):将通知织入到目标对象之后,形成代理对象 aspect(切面):切入点+通知 一:不使用spring的aop注解 以javaEE中的service层为例 UserS