經過AopTestUtils對切面對象進行mock

概述

  當對一個切面類進行測試時,因爲Spring對切面對象生成了proxy對象,此時對切面對象使用ReflectionTestUtils賦值,操做的是proxy對象,而不是真實對象,會使得賦值出問題。能夠經過引入AopTestUtils解決賦值問題。html

AopTestUtils使用思路

  經過AopTestUtils能夠經過切面proxy對象,獲取到切面的真實對象。經過使用ReflectionTestUtils對真實的切面對象修改依賴,到達mock的目的。java

代碼例子

準備切面對象:
IBar:git

package com.github.yongzhizhan.draftbox.springtest.aop;

public interface IBar {
    String perform(String message);
}

Bar:github

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");
    }
}

依賴對象:web

package com.github.yongzhizhan.draftbox.springtest.aop;

/**
 * Dependence class
 * @author zhanyongzhi
 */
public class Dep {
    public String perform(String msg){
        return msg;
    }
}

切面:spring

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");
    }
}

配置文件:spring-mvc

<?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中查看mvc

參考

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

相關文章
相關標籤/搜索