国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

使用Mockito修改Bean的依賴

Elle / 2803人閱讀

摘要:概述在使用單元測試時(shí)經(jīng)常會(huì)遇到某些依賴了外部資源,或者想主動(dòng)繞過真正的方法執(zhí)行返回結(jié)果而快速得到單元測試最終的期望結(jié)果,可能有以下兩種場景,對于,設(shè)單元測試的方法是的方法和方法,在執(zhí)行和方法時(shí)都會(huì)調(diào)用的不同方法,即依賴了一個(gè)場景是完全對進(jìn)行

概述

在使用單元測試時(shí)經(jīng)常會(huì)遇到某些dependency依賴了外部資源,或者想主動(dòng)繞過真正的方法執(zhí)行mock返回結(jié)果而快速得到單元測試最終的期望結(jié)果,可能有以下兩種場景,
對于TestCase A,設(shè)單元測試的方法是Service A的execute1方法和execute2方法,在執(zhí)行execute1和execute2方法時(shí)都會(huì)調(diào)用ServiceB的不同方法,即ServiceA依賴了ServiceB;一個(gè)場景是完全對ServiceB進(jìn)行Mock,如單元測試ServiceA#execute1方法時(shí)都通過Mock返回結(jié)果;一個(gè)場景是部分ServiceB的方法執(zhí)行真實(shí)的業(yè)務(wù)邏輯(如查詢數(shù)據(jù)庫),一部分方法執(zhí)行Mock返回結(jié)果,或Spy,如如單元測試ServiceA#execute2方法時(shí),只mock ServiceB#b2結(jié)果,真正執(zhí)行ServiceB#b1方法。

對TestCase的Service的依賴Bean的完全Mock

當(dāng)對ServiceA的方法執(zhí)行單元測試時(shí),如ServiceA -> ServiceB,此時(shí)對ServiceB進(jìn)行Mock,然后將其設(shè)置到ServiceA的屬性中;后續(xù)ServiceA調(diào)用ServiceB的方法都降得到Mock后的結(jié)果;而對于ServiceB對象的本來的依賴本案暫且將其忽略,后續(xù)改進(jìn);

思路是在TestCase中依賴ServiceA的同時(shí)標(biāo)示Mock ServiceB,待TestCase依賴注入完成后,新建ServiceB的Mock對象替換ServiceA中的ServiceB依賴;

@TestExecutionListeners({MockitoDependencyInjectionTestExecutionListener.class})
public class AServiceMockTest extends BaseTest {
    @Mock
    private BService bservice;
    @Autowired
    private AService aservice;
    @Before
    public void setup(){
        doReturn("mock").when(bservice).b1();
    }
    @Test
    public void test() {
        a.execute1();
    }
}
@Service
public class AServiceImpl implements AService {
    @Autowired
    private BService bservice;
     
    @Override
    public String execute1() {
        return bservice.b1(); //will return mock after Mock
    }
}

當(dāng)a.execute()執(zhí)行時(shí)將調(diào)用aservice的屬性bservice的b1方法,返回結(jié)果就是在setup方法中指定的結(jié)果;

監(jiān)聽TestCase的Service的依賴Bean

當(dāng)對ServiceA進(jìn)行單元測試時(shí),依賴了ServiceB,需要獲取ServiceB的b1方法的真正執(zhí)行結(jié)果,Mock b2方法的結(jié)果,此時(shí)可以采用Spy方式;由于ServiceA依賴了ServiceB,而這個(gè)屬性可能是個(gè)AopProxy對象,并不能直接使用Mockito.mock(bservice)或者M(jìn)ockito.spy(bservice),所以這里@Spy注解指定的是實(shí)現(xiàn)類,通過MockitoDependencyInjectionTestExecutionListener處理后,獲得一個(gè)Spy對象,同時(shí)這個(gè)Spy對象設(shè)置到bservice(AopProxy對象)中去;

@TestExecutionListeners({MockitoDependencyInjectionTestExecutionListener.class})
public class AServiceMockTest extends BaseTest {
    @Spy
    private BServiceImpl bserviceImpl;
    @Autowired
    private AService aservice;
    @Before
    public void setup(){
        doReturn(true).when(bserviceImpl).b2(any(String.class));
    }
    @Test
    public void test() {
        a.execute();
    }
}
@Service
public class AServiceImpl implements AService {
    @Autowired
    private BService bservice;
     
    @Override
    public boolean execute2() {
        String str = bservice.b1();
        return bservice.b2(str);
    }
}
MockitoDependencyInjectionTestExecutionListener的實(shí)現(xiàn)
public class MockitoDependencyInjectionTestExecutionListener extends DependencyInjectionTestExecutionListener {

    private Set injectFields = new HashSet<>();
    private Map mockObjectMap = new HashMap<>();
    @Override
    protected void injectDependencies(TestContext testContext) throws Exception {
        super.injectDependencies(testContext);
        init(testContext);
    }

    /**
     * when A dependences on B
     * mock B or Spy on targetObject of bean get from Spring IoC Container whose type is B.class or beanName is BImpl
     * @param testContext
     */
    private void init(TestContext testContext) throws Exception {

        AutowireCapableBeanFactory factory =testContext.getApplicationContext().getAutowireCapableBeanFactory();
        Object bean = testContext.getTestInstance();
        Field[] fields = bean.getClass().getDeclaredFields();

        for (Field field : fields) {
            Annotation[] annotations = field.getAnnotations();
            for (Annotation annotation : annotations) {
                if(annotation instanceof Mock){
                    Class clazz = field.getType();
                    Object object = Mockito.mock(clazz);
                    field.setAccessible(true);
                    field.set(bean, object);
                    mockObjectMap.put(field.getName(), object);
                } else if(annotation instanceof Spy) {
                    Object fb = factory.getBean(field.getName()); //may be a proxy that can not be spy because $Proxy is final
                    Object targetSource = AopTargetUtils.getTarget(fb);
                    Object spyObject = Mockito.spy(targetSource);
                    if (!fb.equals(targetSource)) { //proxy
                        if (AopUtils.isJdkDynamicProxy(fb)) {
                            setJdkDynamicProxyTargetObject(fb, spyObject);
                        } else { //cglib
                            setCglibProxyTargetObject(fb, spyObject);
                        }
                    } else {
                        mockObjectMap.put(field.getName(), spyObject);
                    }
                    field.setAccessible(true);
                    field.set(bean, spyObject);
                }else if (annotation instanceof Autowired){
                    injectFields.add(field);
                }
            }
        }
        for(Field field: injectFields) {
            field.setAccessible(true);
            Object fo = field.get(bean);
            if (AopUtils.isAopProxy(fo)) {
                Class targetClass = AopUtils.getTargetClass(fo);
                if(targetClass ==null)
                    return;
                Object targetSource = AopTargetUtils.getTarget(fo);
                Field[] targetFields =targetClass.getDeclaredFields();
                for(Field targetField : targetFields){
                    targetField.setAccessible(true);
                    if(mockObjectMap.get(targetField.getName()) ==null){
                        continue;
                    }
                    ReflectionTestUtils.setField(targetSource,targetField.getName(), mockObjectMap.get(targetField.getName()));
                }

            } else {
                Object realObject = factory.getBean(field.getType());
                if(null != realObject) {
                    Field[] targetFields = realObject.getClass().getDeclaredFields();
                    for(Field targetField : targetFields){
                        targetField.setAccessible(true);
                        if(mockObjectMap.get(targetField.getName()) ==null){
                            continue;
                        }
                        ReflectionTestUtils.setField(fo,targetField.getName(), mockObjectMap.get(targetField.getName()));
                    }
                }
            }
        }
    }

    private void setCglibProxyTargetObject(Object proxy, Object spyObject) throws NoSuchFieldException, IllegalAccessException {
        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);
        ((AdvisedSupport) advised.get(dynamicAdvisedInterceptor)).setTarget(spyObject);

    }

    private void setJdkDynamicProxyTargetObject(Object proxy, Object spyObject) throws NoSuchFieldException, IllegalAccessException {
        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);
        ((AdvisedSupport) advised.get(aopProxy)).setTarget(spyObject);
    }
}
maven依賴

JUnit、Mockito

AopTargetUtils

AopTargetUtils工具類參考 在spring中獲取代理對象代理的目標(biāo)對象工具類

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/76729.html

相關(guān)文章

  • Spring、Spring Boot和TestNG測試指南 - 使用Mockito

    摘要:例子使用源代碼我們先給了一個(gè)的實(shí)現(xiàn)然后又規(guī)定了方法的返回值。源代碼也就是說,得益于,我們能夠很方便地對依賴關(guān)系中任意層級(jí)的任意做。 Github地址 Mock測試技術(shù)能夠避免你為了測試一個(gè)方法,卻需要自行構(gòu)建整個(gè)依賴關(guān)系的工作,并且能夠讓你專注于當(dāng)前被測試對象的邏輯,而不是其依賴的其他對象的邏輯。 舉例來說,比如你需要測試Foo.methodA,而這個(gè)方法依賴了Bar.methodB,...

    Alliot 評(píng)論0 收藏0
  • 基于 Redis 分布式鎖

    摘要:首先談到分布式鎖自然也就聯(lián)想到分布式應(yīng)用。如基于的唯一索引。基于的臨時(shí)有序節(jié)點(diǎn)。這里主要基于進(jìn)行討論。該命令可以保證的原子性。所以最好的方式是在每次解鎖時(shí)都需要判斷鎖是否是自己的??偨Y(jié)至此一個(gè)基于的分布式鎖完成,但是依然有些問題。 showImg(https://segmentfault.com/img/remote/1460000014128437?w=2048&h=1365); 前...

    fasss 評(píng)論0 收藏0
  • Spring Boot 單元測試二三事

    摘要:但是,一個(gè)好的單元測試應(yīng)該是毫秒級(jí)的,否則這會(huì)影響的工作方式,這也就是測試驅(qū)動(dòng)開發(fā)的思想。在單元測試中,我們可以像這樣來構(gòu)建一個(gè)實(shí)例。所以,我們在寫單元測試的時(shí)候,應(yīng)該以一種更簡單的方式去構(gòu)建。 本文翻譯自:https://reflectoring.io/unit-...原文作者:Tom Hombergs 譯文原地址:https://weyunx.com/2019/02/04... ...

    xbynet 評(píng)論0 收藏0
  • Spring Boot 2.1.2 & Spring Cloud Greenwich 升級(jí)

    摘要:節(jié)前沒有新業(yè)務(wù)代碼,正好剛發(fā)布,于是開始為期四天的框架代碼升級(jí)。還好并沒有使用它的,配置上有一個(gè)小坑,的是表示而是表示,之前配置成的,如果到的里面那就要拋異常了。 節(jié)前沒有新業(yè)務(wù)代碼,正好Greenwich剛發(fā)布,于是開始為期四天的框架代碼升級(jí)。 之前的版本是 spring boot 1.5.10 , spring cloud Edgware.SR3 依賴升級(jí) 增加依賴管理插件 ap...

    newsning 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<