Mockito介紹與入門(mén)
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自己的業(yè)務(wù)
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掉,這樣就可以測(cè)試我們自己的代碼,也就是ApiService中test方法自己的業(yè)務(wù)圆兵。
Spring中mock任何容器內(nèi)對(duì)象
上面的demo, 我們?nèi)绾蝝ock掉TestApiService中的test方法?
因?yàn)門(mén)estApiService是Spring容器管理的bean, 并且ApiService中使用到TestApiService, 所以我們把ApiService中引用的TestApiService替換成我們的mock對(duì)象即可。
Spring框架有個(gè)反射工具ReflectionTestUtils可以把一個(gè)對(duì)象中屬性設(shè)置為新值仅颇,我們可以使用:
ReflectionTestUtils.setField(apiService, "testApiService", spyTestAPiService);
把我們mock的testApiService放到apiService中剖膳,這樣apiService調(diào)用就是我們mock的對(duì)象了;但是默認(rèn)spring中apiService對(duì)象是代理對(duì)象格侯,不能直接把值設(shè)置到屬性上鼻听,所以我們自己需寫(xiě)個(gè)小工具類(lèi),最后如下:
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自己的業(yè)務(wù)
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 * 獲取 目標(biāo)對(duì)象
58 * @param proxy 代理對(duì)象
59 * @return
60 * @throws Exception
61 */
62 public static Object getTarget(Object proxy) throws Exception {
63 if(!AopUtils.isAopProxy(proxy)) {
64 return proxy;//不是代理對(duì)象
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 }
最后就是注意測(cè)試之后要還原現(xiàn)場(chǎng),把spring對(duì)象還原联四,尤其在跑maven test的時(shí)候撑碴,否則可能會(huì)影響其他人的測(cè)試。
[本文轉(zhuǎn)載自此處][1]
[1]:http://blog.csdn.net/chuntian_feng/article/details/51871808