科技改變生活 · 科技引領未來

                • 首頁
                • 資訊
                • 技術
                • 百科
                • 問答
                • 學習
                • 看看
                • 站長
                • 生活
                • 快訊

                首頁 > 百科 > 產品快訊

                spycall多少錢(談一談單元測試)

                時間:2022-09-27 13:31 作者:馬熙遠

                寫在前面對于我們開發人員來說,單元測試一定不會陌生,但在各種原因下會被忽視,尤其是在我接觸到的項目中,提測階段發現各種各樣的問題,我覺得有必要聊一下單元測試。為了寫而寫的單元測試沒什么價值,但一個好的單元測試帶來的收益是非??陀^的。問題是怎

                spycall多少錢(談一談單元測試)

                寫在前面

                對于我們開發人員來說,單元測試一定不會陌生,但在各種原因下會被忽視,尤其是在我接觸到的項目中,提測階段發現各種各樣的問題,我覺得有必要聊一下單元測試。

                為了寫而寫的單元測試沒什么價值,但一個好的單元測試帶來的收益是非常客觀的。問題是怎么去寫好單元測試?怎么去驅動寫好單元測試?

                一 我們的現狀

                現狀一:多個項目完全沒有單元測試。

                現狀二:開發人員沒有寫單元測試的習慣,或者由于趕業務記錄而沒有時間去寫。

                現狀三:單元測試寫成了集成測試,比如容器、數據庫,導致單元測試運行時間長,失去了意義。

                現狀四:太依賴集成測試。

                以上是我在aone找的兩個項目的測試情況,基本不考慮單元測試就合并發布,形同虛設。

                站在開發的角度講,導致以上問題的原因大概有以下幾點:

                1、開發成本

                對于系統初期,可能要花很多時間去寫新業務,對于老系統又太過龐大,無法下手。

                2、維護成本

                每修改相關的類,或者重構一次代碼,我們就要去修改相應的單元測試。

                3、ROI

                投入產出是不是正收益?可能無論是管理者還是我們開發自己都回質疑這個問題,所以有時候沒有強有力的動力。

                二 怎么解決

                說來說去都是成本的問題,所以我們怎么去解決成本呢?

                那么,我們一切從最開始說起:開發的成本

                一個單元測試的傳統寫法,包含以下幾個方面:

                1. 測試數據 (被測數據,和依賴對象)
                2. 測試方法
                3. 返回值斷言
                  @Test   public void testAddGroup() {     // 數據     BuyerGroupDTO groupDTO = new BuyerGroupDTO();     groupDTO.setGmtCreate(new Date());     groupDTO.setGmtModified(new Date());     groupDTO.setName("中國");     groupDTO.setCustomerId(customerId);     // 方法     Result result = customerBuyerDomainService.addBuyerGroup(groupDTO);     // 返回值斷言     Assert.assertTrue(result.isSuccess());     Assert.assertNotNull(result.getData());   }  

                一個簡單的測試還好,但如果是一邏輯復雜,且入參數據復雜的時候,那寫起來其實挺頭痛的。怎么解放我們程序員的雙手?

                “工欲善其事必先利其器”

                我們以最大的努力降低我們的開發成本,這就涉及到我們測試框架和工具的選擇問題

                1 測試框架選擇

                首先第一個問題就是junit4和junit5的選擇,【從junit4到junit5】 我覺得最便利的一個好處就是可以參數化測試,并且基于參數化測試我們可以更加靈活的配置我們的參數。

                效果如下:

                @ParameterizedTest @ValueSource(strings = { "racecar", "radar", "able was I ere I saw elba" }) void palindromes(String candidate) {     assertTrue(StringUtils.isPalindrome(candidate)); }

                更好的是,junit5提供了擴展,比如我們常用的json格式。這里我們使用json文件作為輸入:

                  @ParameterizedTest   @JsonFileSource(resources = {"/com/cq/common/KMPAlgorithm/test.json"})    public void test2Test(JSonObject arg) {     Animal animal = JSONObject.parseObject(arg.getString("Animal"),Animal.class);      List stringList = JSONObject.parseArray(arg.getString("List"),String.class);      when(testService.testOther(any(Student.class))).thenReturn(stringArg);     when(testService.testMuti(any(List.class),any(Integer.class))).thenReturn(stringList);     when(testService.getAnimal(any(Integer.class))).thenReturn(animal);     String result = kMPAlgorithm.test2();     //todo verify the result   }

                2 mock框架

                然后就是其他mock類的框架了

                Mockito: 語法特別優雅,對于容器類的模擬比較合適,且對于返回值為空的函數調用也提供比較好的斷言。缺點是不能模擬靜態方法(3.4.x以上版本已支持)

                EasyMock: 使用方法類似,但是更嚴格

                PowerMock: 可以作為Mockito的一個補充,比如要測試靜態方法,不過不支持junit5

                Spock: 基于Groovy語言的單元測試框架

                3 數據庫層

                這里主要介紹一下H2數據庫,其基于內存來作為對于關系型數據庫的模擬,運行完成自動釋放,達到隔離的目的。

                主要配置:ddl文件路徑、dml文件路徑。這里不作詳述。

                但對于要不要集成數據庫,很難去定義,它的作用主要是用來驗證sql語法的問題,但是相對來說較重,建議可以用于輕量級的集成測試。

                三 Junit5和Mockito

                后面講到的自動生成使用的框架和業界使用最多的都是MocKito,所以這里重點介紹一下,包括使用時遇到的問題。

                1 使用方法

                分別單獨引入依賴,推薦引入最新版

                1. 使用spring-test全家桶

                junit5的使用方法這里就不多做介紹,主要說一下這個ArgumentsProvider接口,實現它就可以自定義參數化類,類似于自帶的ValueSource、EnumSource等。

                2 Mockito 主要注解介紹

                先問為什么,為什么需要Mockito

                因為:現在的java項目幾乎離不開spring框架,而其最為著名的就是IOC,所有的bean用容器來管理,所以這給我們單元測試帶來一個問題,如果要對bean做單元測試,就需要啟動容器,那么帶來的時間的開銷將會很大。所以Mockito給我門帶來了一系列的解決方法,讓我們可以輕松的對bean 進行測試。

                假設我們要對上面的A.func()進行單元測試。

                @InjectMocks注解

                表示需要注入bean的類,有兩種

                1. 被測試類,這種很容易理解,我們測試這個類,當然也需要向其注入bean。比如上面的A
                2. 被測試類中的,需要執行其真實的方法,但其里面也要主要bean,也就是上面的C,我們需要測試neeExec方法,但我們不關系B的具體細節?,F實中比如事物,并發鎖等。這一類需要Mockito.spy(new C())的形式,不然會報錯

                @Mock

                表示要mock的數據,也就是不真實執行其方法內容,只按照我們的規則執行,或者返回,比如使用when().thenReturn()語法。

                當然也可以,執行真實方法,則需要when().thenCallRealMethod()方式。

                @Spy

                表示所有方法都走真實方式,比如有些工具類,轉換類,我們也寫成了bean的形式(嚴格來說這種需要寫成靜態工具類)。

                @ExtendWith(MockitoExtension.class) public class ATest  {   @InjectMocks   private A a=new A();    @Mock   private B b;   @Spy   private D d;   @InjectMocks   private C c= Mockito.spy(new C());;    @BeforeEach   public void setUp() throws Exception {     MockitoAnnotations.openMocks(this);   }   @ParameterizedTest   @ValueSource(strings = {"/com/alibaba/cq/springtest/jcode5test/needMockService/A/func.json"})    public void funcTest(String str) {     JSonObject arg= TestUtils.getTestArg(str);     a.func();     //todo verify the result   }  }

                3 Mockito和junit5常見問題

                mock靜態方法

                mockito3.4以后開始支持,之前的版本可以使用PowerMock輔助使用

                Mockito版本和java版本兼容問題

                報錯如下

                Mockito cannot mock this class: xxx Mockito can only mock non-private & non-final classes.

                原因是2.17.0及之前的版本與java8是兼容的

                但2.18之后需要使用java11,為了在java8中使用Mockito,則需要引入另一個包

                Jupiter-api版本兼容問題

                Process finished with exit code 255 java.lang.NoSuchMethodError: org.junit.jupiter.api.extension.ExtensionContext.getRequiredTestInstances()Lorg/junit/jupiter/api/extension/TestInstance

                第一個問題是因為junit5中api、engine、params版本不一致導致的。

                第二個問題是因為jupiter-api版本太低的問題,5.7.0以后的版本才支持。

                四 測試代碼自動生成

                選好了框架,我們還是沒有解決我們的問題,“怎么節約開發成本?” ,這一節我們來談這個問題,這也是我主要想表達的。

                對于寫單元測試,一直以來是比較頭痛的事情,要組裝各種各樣的數據,可能還沒跑成功,就被一堆“xxxx不能為null”的報錯搞煩了。因此我們有理由去設想,有沒有辦法去解決這件事情。

                1 業界和集團方案調研

                在做這個事情之前,肯定是要調研有沒有現成的框架。答案是有,但很遺憾,沒有找到完全契合我想要的效果,我們來看一下這些插件:

                public class baseTest {     protected TestService testService;     public String baseTest() {         return testService.testbase(1); // 4     } } public class JCode5 extends baseTest {      public void testExtend(){         String s = testService.testOther(new Student()); //1          // 調用 另一個方法         System.out.println(testBean());         // 調用基類方法         baseTest();     }     // 使用testService     public String testBean() {         testService.testMuti(new ArrayList() {{add(1);}}, 2); //2         return testService.getStr(12); //3     }          public void testGeneric(Person person) {         //test         list.stream().forEach(a -> {             System.out.println(a);         });         for (int i = 0; i < 2; i++) {             Long aLong = testService.getLong("1213"                 , "12323");             System.out.println(aLong);         }         System.out.println(testBean());     } } public class TestService {     public String testbase(Integer integer) {         return "Testbase";     }     public List testMuti(List a, Integer c) {         List res = new ArrayList<>();         res.add(a.toString() + c + "test muti");         return res;     }      public String getStr(Integer integer) {         return "TestService" + getInt();     }      public String testOther(Student student) {         return student.getAge() + "age";     }  }

                如上,testExtend一共調用了testService的4個方法,我們對比下各個插件生成的代碼。

                TestMe

                    @Test     void testTestExtend() {         when(testService.getStr(anyInt())).thenReturn("getStrResponse");         when(testService.testMuti(any(), anyInt())).thenReturn(Arrays.asList("String"));         when(testService.testOther(any())).thenReturn("testOtherResponse");         jCode5.testExtend(Integer.valueOf(0));     }     @Test     void testTestGeneric() {         when(testService.getStr(anyInt())).thenReturn("getStrResponse");         when(testService.getLong(anyString(), anyString())).thenReturn(Long.valueOf(1));         when(testService.testMuti(any(), anyInt())).thenReturn(Arrays.asList("String"));          jCode5.testGeneric(new Person());     }

                1、生成的代碼基本符合邏輯,包括需要mock的bean的邏輯都生成了。

                2、但它把最重要的一環,也就是數據省略了,只是單純的用了構造函數的形式。這顯然對于我們DDD模型不適應。

                3、另外他沒用用到junit5的一些特性,比如參數化測試。

                4、對于testExtend的方法,它只識別了3個方法。沒有識別父類的調用。

                JunitGenerate

                只能生成基礎的框架代碼,對于我想mock的邏輯、以及測試方法都沒有生成,用處不大。

                @Test public void testTestExtend() throws Exception {  //TODO: Test goes here...  }

                Squaretest

                生成的方法非常豐富,且一個非常厲害的一點,它能生成多個分支,比如代碼邏輯中有if條件,它能生成兩個測試,從而走不通的分支。

                但是,最大的缺點是“收費軟件,不開源”,這就決定了我們沒法用它,除非是特別需要。另外測試用過程中還發現了一些其他問題,比如對于繼承,重載之類的問題,它解決的也不是很好,往往識別不了需要調用的方法。

                雖然無法使用,但還是可以借鑒。

                五 打造代碼自動生成最佳方案

                既然市場上的插件都不是特別合適,就決定寫一個適合自己項目的插件(暫時命名JCode5)。有興趣的也可以自己試試。

                1 插件安裝

                idea插件市場下載,搜索JCode5

                2 插件使用

                插件有三個功能

                1. 生成測試代碼,也就是生成單元測試。
                2. 生成json數據,通常用來生成測試數據,比如model。用來參數化測試。
                3. 增加測試方法,隨著業務開發,類可能增加一下功能方法,這個時候相應的可以增加測試方法

                定位到需要測試的類,快捷鍵或菜單定位到generater,如下,選擇JCode5.

                生成測試類

                目前支持三個選項,后續會逐漸完善

                另外兩個功能類似,直接嘗試使用一下就行。

                生成的結果---類+json數據

                  @ParameterizedTest   @ValueSource(strings = {"/com/cq/common/JCode5/testExtend.json"})    public void testExtendTest(String str) {     JSonObject arg= TestUtils.getTestArg(str);     Integer i = arg.getInteger("Integer");      // 識別泛型活著集合類     List stringList = JSONObject.parseArray(arg.getString("List"),String.class);      String stringArg = arg.getString("String");      String stringArg1 = arg.getString("String");      String stringArg0 = arg.getString("String");      // 識別四個方法,包括父類調用、其他方法調用     when(testService.testbase(any(Integer.class))).thenReturn(stringArg);     when(testService.testMuti(any(List.class),any(Integer.class))).thenReturn(stringList);     when(testService.getStr(any(Integer.class))).thenReturn(stringArg0);     when(testService.testOther(any(Student.class))).thenReturn(stringArg1);     jCode5.testExtend(i);     //todo verify the result   }

                如上除了生成基本的代碼,另外會生成測試數據,它會將該方法所需要的測試數據全都生成在一個json文件當中,完全實現

                “數據和代碼的分離”

                如testExtend.json:

                {   "Integer":1,   "String":"test",   "List":[     "test"   ] }

                補充判定語句

                這一塊前期考慮對于不同的方法有不同的校驗,所以目前想的還是開發者自己去寫驗證代碼。

                注意事項

                在自動生成完代碼之后,雖然可以運行,但如我們前面提到的,為了寫單元測試而寫的單元測試是沒什么價值的,我們的最終目的是為了寫一個好的測試。代碼自動生成,但它終究能力有限,所以還是需要我們自己再去驗證,比如

                1. 該插件生成的代碼需要junit5和mockito的支持,使用時需要引入相關的依賴
                2. 增加assert校驗邏輯,看是不是想要的結果,目前插件不會自動生成assertEquals等斷言代碼。
                3. 運用參數化測試能力,復制一份生成的json文件并修改輸入數據,多組測試

                3 插件實現介紹

                主要的實現思路,參考了dubbo的SPI的源碼,也就是自動實現自適應SPI那部分,簡單點說就是反射獲取代碼邏輯,然后生成測試代碼。

                4 后期規劃

                1、mock數據可定制,目前的想法是

                • 固定值比如目前的String: test、Integer和boolean: 0、1
                • 測試者使用配置模版,比如txt文件包含keyValue對
                • 使用Faker,對于name、email、phone這種特定傾向的數據進行特色自動生成

                2、自動分支測試,這一塊的想法目前主要針對if來做,需要一定的時間。

                3、其他

                六 寫在最后

                對于代碼自動生成,還是有很多東西可以做的,但有些問題還尚待解決,希望能盡最大努力解放我們的雙手,也能提高我們單元測試的質量。

                已在我們項目中使用此模式增加135個測試用例(除去mock的單模塊達到70%):速度比集成測試(pandora、spring等)提升一個等級。代碼的覆蓋率相對可觀。

                作者 | 有塵

                原文鏈接:https://developer.aliyun.com/article/867079?utm_content=g_1000324519

                本文為阿里云原創內容,未經允許不得轉載。

                相關話題

                • 做玻尿酸隆鼻大約多少錢一支(能賣到2萬)
                • 華為mate10手機屏幕多少錢(什么是)
                • 安裝牙齒多少錢一顆(很糾結)
                • 微信零錢通可以放多少錢(零錢通和余額寶哪個收益高)
                • 平板換個屏幕大概多少錢(精心包裝的高價教育平板)
                • 黑色法斗價格多少錢一只(法斗顏色這么多)
                • 車多少錢一輛(搬家怎么選車型)
                • 蒼術一斤多少錢(蒼術高價仍將持續)
                • 電動車的電機多少錢一個(這2款4000元檔位的電摩)
                • 歌廳音響設備多少錢一套(家里唱歌要準備什么)
                • 東風啟辰d60自動擋多少錢(端午節來臨)
                • 懸浮板多少錢一平方(Ayutt)
                • 裝修費用一般要多少錢(第一次經歷裝修)
                • 讀研究生學費多少錢一年(研究生曬)
                • 狗狗剪毛多少錢一次(帶狗狗剪毛)
                • 請搬家公司需要多少錢(搬家公司怎么收費的)
                • 開一個沙場需要多少錢(開一個小型人工沙場)
                • 小白鼠血清多少錢一升(做農業太難)
                • 鋅回收多少錢一斤(廢金屬價格2022年6月7日廢鋁廢錫廢鉛廢電瓶回收價格調整信息)
                • 牙齒冠修復一顆多少錢(你補過牙嗎)

                熱門推薦

                • 即日起,淘寶88VIP用戶能無限次退貨包郵!
                • 華為Pura系列今日10:08分上架,現已買斷貨!
                • OpenAI:新GPT-4 Turbo模型現可付費ChatGPT用戶使用!
                • 華為門店接受P70盲訂?或在線上直接開賣!
                • 曝因OLED面板供應不足,iPad Pro 2024或將延期至5月份!
                • 蘋果開發者大會定檔端午節,知情人士透露或有AI 要素!
                • 阿里通義千問免費開放1000萬字長文檔處理功能!
                • 哈弗二代大狗 Hi4 版車型 3 月25 日發布!
                • 小米汽車28日見,上市即交付,價格仍是迷!
                • 支付寶近期將上線多語言翻譯等服務,開啟國家化交易!
                • 華為本月或將發布75英寸V5 智慧屏等新品!
                • 奇瑞iCAR 03硬派越野新車上市,售價10.98萬起收獲不少好評!
                • 華為全新小折疊旗艦HUAWEI Pocket 2正式發布,時尚、高端、有內涵!
                • 比亞迪秦 PLUS 榮耀版上市,預計售價7.98萬元起!
                • 百度搜索推出AI拜年新功能,支持多種風格更有趣!
                • 華為全國都能開的高階智駕來了!推送計劃正在火熱進行中......
                • 保時捷將正式發布第二個純電動車系,配置值得期待!
                • 智能汽車被重新定義,比亞迪讓智能汽車更智慧化!
                • 三星Galaxy S24系列發布:799美元起,AI賦能,四色可選!
                • CES2024:三星新一代十字門Flex冰箱為用戶帶來智慧廚房新體驗!

                馬熙遠

                關注
                免責聲明:本文章由會員“馬熙遠”發布,如果文章侵權,請聯系我們處理,本站僅提供信息存儲空間服務 如因作品內容、版權和其他問題請于本站聯系

                關注排行榜

                1. 1即日起,淘寶88VIP用戶能無限次退貨包郵!
                2. 2華為Pura系列今日10:08分上架,現已買斷貨!
                3. 3OpenAI:新GPT-4 Turbo模型現可付費ChatGPT用戶使用!
                4. 4華為門店接受P70盲訂?或在線上直接開賣!
                5. 5曝因OLED面板供應不足,iPad Pro 2024或將延期至5月份!
                6. 6蘋果開發者大會定檔端午節,知情人士透露或有AI 要素!
                7. 7阿里通義千問免費開放1000萬字長文檔處理功能!
                8. 8哈弗二代大狗 Hi4 版車型 3 月25 日發布!
                9. 9小米汽車28日見,上市即交付,價格仍是迷!
                10. 10支付寶近期將上線多語言翻譯等服務,開啟國家化交易!

                編輯精選

                Copyright ?2009-2022 KeJiTian.Com, All Rights Reserved

                版權所有 未經許可不得轉載

                增值電信業務經營許可證備案號:遼ICP備14006349號

                網站介紹 商務合作 免責聲明 - html - txt - xml

                感谢您访问我们的网站,您可能还对以下资源感兴趣:

                经典香港**毛片免费看_91精品一区二区综合在线_欧美人与性动交a欧美精品_国产小视频在线看