zoukankan      html  css  js  c++  java
  • 通过AopTestUtils对切面对象进行mock

    概述

    当对一个切面类进行测试时,由于Spring对切面对象生成了proxy对象,此时对切面对象使用ReflectionTestUtils赋值,操作的是proxy对象,而不是真实对象,会使得赋值出问题。可以通过引入AopTestUtils解决赋值问题。

    AopTestUtils使用思路

    通过AopTestUtils可以通过切面proxy对象,获取到切面的真实对象。通过使用ReflectionTestUtils对真实的切面对象修改依赖,到达mock的目的。

    代码例子

    准备切面对象:
    IBar:

    package com.github.yongzhizhan.draftbox.springtest.aop;
    
    public interface IBar {
        String perform(String message);
    }
    

    Bar:

    package com.github.yongzhizhan.draftbox.springtest.aop;
    
    import org.springframework.beans.factory.annotation.Autowired;
    
    public class Bar implements IBar {
        @Autowired
        Dep dep;
    
        @Override
        public String perform(final String message) {
            System.out.println("run bar " + message);
            return dep.perform("aspect");
        }
    }
    

    依赖对象:

    package com.github.yongzhizhan.draftbox.springtest.aop;
    
    /**
     * Dependence class
     * @author zhanyongzhi
     */
    public class Dep {
        public String perform(String msg){
            return msg;
        }
    }
    

    切面:

    package com.github.yongzhizhan.draftbox.springtest.aop;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    
    /**
     * 切面
     */
    @Aspect
    public class BarAspect {
        @Before(value = "execution(* com.github.yongzhizhan.draftbox.springtest.aop.Bar.perform(..))")
        public void beforeSayHello(JoinPoint vJoinPoint){
            System.out.println("aspect before "+vJoinPoint.getArgs()[0]);
        }
    }
    

    测试例子

    package com.github.yongzhizhan.draftbox.springtest;
    
    import com.github.yongzhizhan.draftbox.springtest.aop.Bar;
    import com.github.yongzhizhan.draftbox.springtest.aop.BarAspect;
    import com.github.yongzhizhan.draftbox.springtest.aop.Dep;
    import com.github.yongzhizhan.draftbox.springtest.aop.IBar;
    import org.junit.Assert;
    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.mockito.InjectMocks;
    import org.mockito.Mock;
    import org.mockito.MockitoAnnotations;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationContext;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    import org.springframework.test.util.AopTestUtils;
    import org.springframework.test.util.ReflectionTestUtils;
    
    import static org.mockito.Mockito.when;
    
    /**
     * 通过AopTestUtils解决ReflectionTestUtils赋值切面对象的问题
     * @author zhanyongzhi
     */
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath*:**web-config.xml")
    public class AopTestUtilsTest {
        @Mock
        Dep dep;
    
        @Autowired
        private BarAspect barAspect;
    
        @Autowired
        ApplicationContext applicationContext;
    
        @Autowired
        @InjectMocks
        IBar bar;
    
        @Before
        public void setUp(){
            MockitoAnnotations.initMocks(this);
    
            //对象默认返回aspect,修改为返回mock
            when(dep.perform("aspect")).thenReturn("mock");
        }
    
        @Test
        public void testDefault(){
            String tRet = bar.perform("hello");
    
            //mock注入无效,仍然返回aspect
            if(!"aspect".equals(tRet))
                Assert.fail("perform return not equeal aspect");
        }
    
        @Test
        public void testAopUtils(){
    
            //获取真实的代理对象
            Bar tBar = AopTestUtils.getTargetObject(bar);
            ReflectionTestUtils.setField(tBar, "dep", dep);
    
            String tRet = bar.perform("hello");
    
            //此时才真正mock到
            if(!"mock".equals(tRet))
                Assert.fail("perform return not equeal mock");
        }
    }
    

    配置文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:mvc="http://www.springframework.org/schema/mvc"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
                   http://www.springframework.org/schema/context
                   http://www.springframework.org/schema/context/spring-context-4.1.xsd
                   http://www.springframework.org/schema/mvc
                   http://www.springframework.org/schema/mvc/spring-mvc.xsd
                   http://www.springframework.org/schema/aop
                   http://www.springframework.org/schema/aop/spring-aop-4.1.xsd">
    
        <!-- scan the package and the sub package -->
        <mvc:annotation-driven/>
        <context:component-scan base-package="com.github.yongzhizhan.draftbox.springtest"/>
    
        <bean id="bar" class="com.github.yongzhizhan.draftbox.springtest.aop.Bar"/>
        <bean id="dep" class="com.github.yongzhizhan.draftbox.springtest.aop.Dep"/>
        <bean id="barAspect" class="com.github.yongzhizhan.draftbox.springtest.aop.BarAspect"/>
    
        <aop:aspectj-autoproxy/>
    </beans>
    

    在github中查看

    参考

    spring-aop-aspect-not-working-using-mockito
    mockito-and-spring-proxies
    is-it-possible-to-unproxy-a-spring-bean

  • 相关阅读:
    MFC中获取系统当前时间
    我的定时关机程序(MFC实现) .
    编写一个闹钟和定时关机工具(MFC VS2010)
    Spark-SQL之DataFrame操作
    RDD操作
    Scala之Object (apply) dycopy
    Intellij IDEA 快捷键整理(dyCopy)
    python第三方包的windows安装文件exe格式
    pythong 中的 __call__
    触发器学习笔记(:new,:old用法)
  • 原文地址:https://www.cnblogs.com/xiaohunshi/p/5705138.html
Copyright © 2011-2022 走看看