成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

靜態(tài)方法,mock 還是不 mock,這是個(gè)問(wèn)題

waterc / 959人閱讀

摘要:?jiǎn)卧獪y(cè)試中是否要靜態(tài)方法,一直爭(zhēng)論不休,網(wǎng)上有一個(gè)一個(gè)又一個(gè)的討論,各種意見(jiàn)都有。真要用來(lái)靜態(tài)方法,一般都是結(jié)合使用。等工具不支持靜態(tài)方法,原理上是因?yàn)樗鼈兌际腔诘?,只能通過(guò)創(chuàng)建子類或?qū)崿F(xiàn)接口的方式去。什么靜態(tài)方法構(gòu)造函數(shù),隨時(shí)隨地想就。

王者 Mockito

不知從何時(shí)開(kāi)始,Mockito 成了 Java 的單元測(cè)試框架王者,目前(2019年7月)Github 上 star 數(shù)直逼 10K??纯雌渌膯卧獪y(cè)試工具:PowerMock 2K(無(wú)疑是沾了 Mockito 的光),easymock 600,JMockit 300。跟 Mockito 一比,好可憐啊,一個(gè)能打的都沒(méi)有。

Mockito 當(dāng)然很好。我從2012年還是2013年開(kāi)始用 Mockito,看著它從 1.0x 版本一路走來(lái),今年晚些時(shí)候估計(jì)會(huì)正式發(fā)布 3.0 版本。應(yīng)該有不少人都跟我有類似的體驗(yàn),從 Mockito 開(kāi)始接觸 mock / stub,一邊贊嘆 Mockito 語(yǔ)法的簡(jiǎn)練,一邊享受著 mock 帶來(lái)的單元測(cè)試的便利性??傉f(shuō)單元測(cè)試應(yīng)該要隔離外部依賴和實(shí)現(xiàn),很難想象,如果沒(méi)有 mock,怎么寫單元測(cè)試呢?

public void test() {
    when(userDao.update(any(User.class))).thenReturn(1);
    int actual = userService.update(aUser);
    Assert.assertTrue(acutal > 0);
    verify(userDao).update(aUser);
}

看看上面這個(gè) Mockito 的例子,when(...).thenReturn(...),verify(...).doSomething(),這代碼就像人類語(yǔ)言,多么簡(jiǎn)明易懂!

但是(沒(méi)錯(cuò)轉(zhuǎn)折來(lái)了),已經(jīng)2019年了,Mockito 依然不支持 mock 靜態(tài)方法、構(gòu)造方法等。你可以說(shuō),這是設(shè)計(jì)理念,Mockito 首頁(yè)上一直寫著一句話 "Don’t mock everything" ,認(rèn)為說(shuō)應(yīng)該做好功能代碼的設(shè)計(jì),盡量避免靜態(tài)方法等,盡量使你的代碼易于測(cè)試。這個(gè)理念,在理論上沒(méi)問(wèn)題,但這么多年的開(kāi)發(fā)經(jīng)驗(yàn)告訴我,理想歸理想,實(shí)際上要你去維護(hù)的遺留代碼總是一籮筐一籮筐的,避無(wú)可避。

Static methods, to mock or not to mock, that is the question

單元測(cè)試中是否要 mock 靜態(tài)方法,一直爭(zhēng)論不休,網(wǎng)上有 一個(gè) 一個(gè) 又一個(gè) 的討論,各種意見(jiàn)都有。

我的個(gè)人意見(jiàn),跟 這個(gè)觀點(diǎn) 一樣,我認(rèn)為測(cè)試工具不應(yīng)該替用戶決定什么是好、什么是不好,而應(yīng)該盡量提供選擇,讓用戶自行判斷、采取合適的方案。理論很美好,但實(shí)際情況就是,google 搜 "mockito how to mock static methods",有近15萬(wàn)條結(jié)果,可想而知,全世界的開(kāi)發(fā)者在這個(gè)問(wèn)題上浪費(fèi)了多少時(shí)間。

真要用 Mockito 來(lái) mock 靜態(tài)方法,一般都是結(jié)合 PowerMock 使用。這兩年 PowerMock 發(fā)展的怎么樣我不太清楚,但14、15年那會(huì)兒我用過(guò) PowerMock,感受就是,真他媽累啊!理論上來(lái)說(shuō)是可以的,但實(shí)際做起來(lái)就總是各種問(wèn)題,然后各種 google 、解決,然后又繼續(xù)各種問(wèn)題,排查的我都快懷疑人生了。最終我是放棄了 PowerMock 的,這么費(fèi)力地去結(jié)合兩個(gè)工具一起用,往后很難說(shuō)還有多少坑。

Mockito、EasyMock 等工具不支持 mock 靜態(tài)方法,原理上是因?yàn)樗鼈兌际腔?cglib 的,只能通過(guò)創(chuàng)建子類或?qū)崿F(xiàn)接口的方式去 mock。那除了 cglib ,就沒(méi)有其他的 mock 實(shí)現(xiàn)方法了嗎?當(dāng)然有,修改字節(jié)碼呀!

另辟蹊徑的 JMockit

和其他大多數(shù)使用 cglib 實(shí)現(xiàn)的單元測(cè)試工具不同,JMockit 使用 JDK6 的 java.lang.instrument 包和 ASM,動(dòng)態(tài)地在運(yùn)行時(shí)修改字節(jié)碼,從而實(shí)現(xiàn) "Mock Anything" 。什么靜態(tài)方法、構(gòu)造函數(shù),隨時(shí)隨地想 mock 就 mock。一個(gè) JMockit ,解決了 Mockito + PowerMock 兩個(gè)工具都解決不了的問(wèn)題,那為啥不用 JMockit 呢?JMockit 為啥流行不起來(lái)呢?

public class UserServiceTest {

    @Tested
    private UserService userService;
    @Injectable
    private UserDao userDao;

    public void test() {
        new Expectations() {
            {
                userDao.update(withInstanceOf(User.class));
                result = 1;
            }
        };

        int actual = userService.update(aUser);
        Assert.assertTrue(acutal > 0);

        new Verifications() {
            {
                userDao.update(withInstanceOf(User.class));
            }
        };
    }
}

功能更強(qiáng)大的 JMockit 卻流行不起來(lái),我覺(jué)得其中一個(gè)原因,是它的語(yǔ)法不太友好??纯瓷厦孢@個(gè) JMockit 的例子,這坨 new Expectations(){...}new Verifications(){...} 是什么鬼?匿名類?為啥里面又有一層大括號(hào)?別說(shuō)測(cè)試代碼了,在普通的功能代碼中,我們都極少見(jiàn)到這樣的語(yǔ)法。多數(shù)人可能覺(jué)得不習(xí)慣,然后就此打住,放棄 JMockit 了。

JMockit 的這種語(yǔ)法,是基于它的 record-replay-verify 模型。new Expectations() 是錄制期望,new Verifications() 是校驗(yàn),二者中間的就是回放——正常調(diào)用業(yè)務(wù)方法。而在匿名內(nèi)部類類中間的那層大括號(hào),是 Java 的“實(shí)例初始化塊” (Instance Initialization Blocks),我們平時(shí)可能用“靜態(tài)初始化塊”比較多,“實(shí)例初始化塊”確實(shí)較少見(jiàn),它的其中一種用途,就是用來(lái)初始化匿名內(nèi)部類,因?yàn)槟涿麅?nèi)部類不能有構(gòu)造函數(shù)。理解了這些語(yǔ)法之后,其實(shí) JMockit 不難懂,用法跟其他測(cè)試框架也大致一樣,就是功能更強(qiáng)大了。

JMockit 不夠流行的另一個(gè)原因,我猜可能跟社區(qū)有關(guān)。沒(méi)辦法,Mockito 太受歡迎了,社區(qū)一片火熱,貢獻(xiàn)者一大堆。反觀 JMockit,雖然開(kāi)源,但只有原作者 Rogério Liesenfeld 自己一個(gè)人在開(kāi)發(fā)維護(hù)。這種單人維護(hù)的項(xiàng)目,說(shuō)不定哪一天就停更了,大家都會(huì)有這種擔(dān)憂。我也擔(dān)心啊,但看看近幾年 JMockit 的 release notes,基本上固定每一、兩個(gè)月一次發(fā)布,并且還會(huì)提前訂好下一次發(fā)布的計(jì)劃,真想對(duì)作者說(shuō)一句:老哥,穩(wěn)!所以,至少目前看來(lái),JMockit 的穩(wěn)定性、活躍性是不用擔(dān)心的,畢竟有個(gè)這么穩(wěn)的作者。

JUnit5 + JMockit + Surefire + Jacoco 的配置例子

想要安心用上 Junit5 和 JMockit,還想要單元測(cè)試覆蓋率?那還是有些坑要踩的。以 Maven 為例,有幾個(gè)留意點(diǎn):

默認(rèn)的 maven-surefire-plugin (運(yùn)行單元測(cè)試的) 的版本不支持 JUnit5,得手動(dòng)指定新版本號(hào)才行。

想用 jacoco-maven-plugin 得到單元測(cè)試覆蓋率的話,因?yàn)?jacoco 也用了修改字節(jié)碼的方案,默認(rèn)配置下會(huì)和 JMockit 有沖突。需要一些額外配置才行,具體參考下面的例子。

完整的 Maven 配置例子:



    4.0.0

    io.github.renial
    java-utils
    1.0.0
    jar
    java-utils

    
        UTF-8
        UTF-8
        1.8
        1.8

        1.46
        5.4.2 
        2.22.2 
        0.8.4
    

    
        
            org.jmockit
            jmockit
            ${jmockit.version}
            test
        
        
            org.junit.jupiter
            junit-jupiter
            ${jupiter.version}
            test
        
    

    
        
            
                org.apache.maven.plugins
                maven-surefire-plugin
                ${surefire.version}
                
                
                
                    
                        -javaagent:${settings.localRepository}/org/jmockit/jmockit/${jmockit.version}/jmockit-${jmockit.version}.jar -javaagent:"${settings.localRepository}"/org/jacoco/org.jacoco.agent/${jacoco.version}/org.jacoco.agent-${jacoco.version}-runtime.jar=destfile=${project.build.directory}/jacoco.exec
                    
                
            

            
                org.jacoco
                jacoco-maven-plugin
                ${jacoco.version}
                
                    
                    
                    
                    
                    
                        
                            prepare-agent
                        
                    
                    
                        report
                        test
                        
                            report
                        
                    
                
            
        
    

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/75656.html

相關(guān)文章

  • Android單元測(cè)試 - 幾個(gè)重要問(wèn)題

    摘要:言歸正傳,上一篇文章單元測(cè)試如何開(kāi)始介紹了幾款單元測(cè)試框架基本用法依賴隔離概念,本篇主要解答單元測(cè)試中幾個(gè)重要問(wèn)題。在單元測(cè)試交流微信群,很多新進(jìn)來(lái)的小伙伴,都會(huì)幾個(gè)大同小異的問(wèn)題。 showImg(/img/bVEpaD?w=1080&h=715); 原文鏈接:http://www.jianshu.com/p/f5d197a4d83a 前言 已經(jīng)一個(gè)月沒(méi)寫文章了,由于9月份在plan...

    ChristmasBoy 評(píng)論0 收藏0
  • moky = (mock + proxy) // 一個(gè)簡(jiǎn)潔通用的前后端協(xié)作工具

    摘要:現(xiàn)在一般需要分前后端,因?yàn)榇罅壳岸丝蚣芎凸ぞ哝湹挠咳敫词切枨髲?fù)雜了,讓前端可以跟后端獨(dú)立開(kāi)來(lái)。但是,無(wú)論是前端去寫模板,亦或是完全前后端分離去寫,都脫離不了與后端進(jìn)行數(shù)據(jù)交互。 showImg(https://segmentfault.com/img/remote/1460000007317424?w=350&h=113); --> GitHub地址 舊石器時(shí)代,Web 開(kāi)發(fā)并不會(huì)去...

    miqt 評(píng)論0 收藏0
  • 談?wù)勄昂蠖说姆止f(xié)作

    摘要:針對(duì)上面看到的問(wèn)題,現(xiàn)在也有一些團(tuán)隊(duì)在嘗試前后端之間加一個(gè)中間層比如淘寶的。淘寶有很多類似的文章,這里不贅述。淘寶團(tuán)隊(duì)做了兩套接口文檔的維護(hù)工具,以及,不知道有沒(méi)有對(duì)外開(kāi)放,兩個(gè)東西都是基于的一個(gè)嘗試,各有優(yōu)劣。 原文出處: 小胡子哥的博客(@Barret李靖) 前后端分工協(xié)作是一個(gè)老生常談的大話題,很多公司都在嘗試用工程化的方式去提升前后端之間交流的效率,降低溝通成本,并且也開(kāi)發(fā)了...

    Scholer 評(píng)論0 收藏0
  • 談?wù)勄昂蠖说姆止f(xié)作

    摘要:針對(duì)上面看到的問(wèn)題,現(xiàn)在也有一些團(tuán)隊(duì)在嘗試前后端之間加一個(gè)中間層比如淘寶的。淘寶有很多類似的文章,這里不贅述。淘寶團(tuán)隊(duì)做了兩套接口文檔的維護(hù)工具,以及,不知道有沒(méi)有對(duì)外開(kāi)放,兩個(gè)東西都是基于的一個(gè)嘗試,各有優(yōu)劣。 原文出處: 小胡子哥的博客(@Barret李靖) 前后端分工協(xié)作是一個(gè)老生常談的大話題,很多公司都在嘗試用工程化的方式去提升前后端之間交流的效率,降低溝通成本,并且也開(kāi)發(fā)了...

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

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

0條評(píng)論

閱讀需要支付1元查看
<