您的位置:首页 > 编程语言 > Java开发

spring中使用mockito

2015-11-25 14:48 399 查看

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:

按 Ctrl+C 复制代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:testApplicationContext.xml" })
public class SpringMockitoTest {

@Autowired
private ApiService apiService;
@Mock
private TestApiService spyTestApiService;
@Autowired
private TestApiService testApiService;

@Before
public void initMocks() throws Exception {
MockitoAnnotations.initMocks(this);
ReflectionTestUtils.setField(AopTargetUtils.getTarget(apiService), "testApiService", spyTestApiService);
when(spyTestApiService.connect()).thenReturn("ok");
}

@After
public void clearMocks() throws Exception {
ReflectionTestUtils.setField(AopTargetUtils.getTarget(apiService), "testApiService", testApiService);
}

@Test
public void should_success_when_testApiService() {
String result = apiService.test();
Assert.assertEquals("oktest", result);
}
}

@Component
public class ApiService {

@Autowired
private TestApiService testApiService;

public String test() {
String connect = testApiService.connect();
connect += "test";//test自己的业务
return connect;
}
}

@Component
public class TestApiService {
public String connect() {
return "error";
}

public String findFromDb() {
return "db_data";
}
}

public class AopTargetUtils {
/**
* 获取 目标对象
* @param proxy 代理对象
* @return
* @throws Exception
*/
public static Object getTarget(Object proxy) throws Exception {
if(!AopUtils.isAopProxy(proxy)) {
return proxy;//不是代理对象
}
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");
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;
}
}
按 Ctrl+C 复制代码

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

作者:syxChina

出处:http://syxchina.cnblogs.com
www.jingruigroup.com

本文版权归作者、博客园和百度空间共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则作者会诅咒你的。

如果您阅读了我的文章并觉得有价值请点击此处,谢谢您的肯定1。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: