zoukankan      html  css  js  c++  java
  • 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的时候,否则可能会影响其他人的测试。

  • 相关阅读:
    098实战 Job的调度
    maven在windows下的安装
    Map的知识点梳理(不包含collections工具类)
    001 LRU-缓存淘汰算法
    Android渲染机制和丢帧分析
    Android性能优化典范
    正确使用Android性能分析工具——TraceView
    android View 绘制完成监听
    那些年我们用过的显示性能指标
    view, surfaceView, invalidate, postInvalidate, 刷新屏幕
  • 原文地址:https://www.cnblogs.com/syxchina/p/4150879.html
Copyright © 2011-2022 走看看