單元測試相關:spring test、mockito、h2

單元測試相關:spring test、mockito、h2

背景

本文討論單元測試,在單測中遇到的迷惑。單測中測一次就刪除數據下次就沒法再測怎麼辦,第三方的接口很不穩定我們要怎麼測,整個業務規則這麼多限制和要求怎麼辦? 你領導壓縮工期沒有足夠單測的時間怎麼辦?

關於mockito和h2相關的,後續再發文,敬請不要期待,later is never~

囉嗦

先總結一波目前單測遇到的問題,比較雜,想到什麼寫什麼,羅囉嗦

  • 無spring容器啓動的單元測試,基本沒什麼用,因爲現在的project都是用spring的,你不注入bean根本就沒法測

  • 有spring容器啓動的單測,我叫 spring test(你們是怎麼稱呼的?)

  • 國內程序員做單測,很少用斷言,基本上都是運行單測並打印結果,肉眼觀察結果對不對。這是個習慣問題

  • 國內領導很少給開發任務留單測的時間,有時候測試花的時間可能比開發還要多,但是很多領導沒這樣的意識,從而導致單測被草草執行,通常成爲時間不足壓縮的對象。所以追求覆蓋率的單測常常流於形式或者應付(單測保證都難還要求覆蓋率)。但是話說回來,寫單測還是有好處的,靜下心,靜下心。。。

  • 單測,很多人都是測service層的接口,而不是從Controller層開始測,從而可能導致有些入參判斷邏輯沒測到(特別是在Controller寫重邏輯的)

  • 單測,可以直接調用Controller方法進行測試,但是這種情況是接口的直接調用,所以對於@RequestParam 和 hibernate-validator(jsr303)這些校驗,都測不到(因不觸發檢測),所以必鬚髮起http請求測

  • 發起http請求測,可以用spring帶的MockMvc,這種情況jsr303的參數校驗是可以被激活的,會測得全一點

  • 對於一些接口,特別是第三方的接口,我們可以用mockito等框架進行mock測試。這類型的接口同樣要麼還在開發中未ready,要麼是未部署或環境問題,或運行中響應慢等等因素可能會導致單測失敗,推薦mock掉。

  • 單測後,數據有可能被改變,我們怎麼樣回滾? 有些測試是有前置條件的,比如查某個數據,查不到時時接口無法繼續,那我們怎麼測試? 大家共用單測的數據庫,你的數據是可能被同事刪掉的

    • 使用@Translational註解@Test方法,可以回滾數據,這樣可以防止單測後數據改變

    • 可以在單測 “查詢接口” 的時候,先插入數據,這樣每次查詢時都存在

    • 用內存數據庫h2,我們換了思路,不操作實際的庫,操作這個內存庫

      但是前提是這個內存數據庫有這些表結構和數據

      • h2提供了在單測前執行sql腳本初始化所需表和數據的功能,這樣就有表和數據了。(整理建表語句、insert語句、解決sql寫法的差異是個耗時工作

        TIP:
        h2可以設置MODE是MYSQL、PostgreSQL等,有點設置方言的意思,即把h2當成你想要的類型的數據庫,這樣特殊寫法的sql才能執行成功(例如mysql裏可以用on duplidate,但h2裏會報錯,指定MODE=MYSQL後可以解決)
        
        `spring.datasource.url=jdbc:h2:mem:test;MODE=MYSQL`
        
        但是這個MODE 不是指定了庫的種類就完事,例如,即使MODE=PostgreSQL,執行本不該報錯的`on conflict` 語句時還是報錯。又如DDL建表,從Navicat導出來的,也不是不加修改就可執行成功,這也是麻煩點
        
      • 還有一個辦法,是通過jpa hibernate的反向工程生成表結構,這樣就不需要整理表結構(美好的願望

        通過jpa hibernate,在數據庫表POJO,寫上一定的註解,開啓hibernate的反向工程,似乎能夠解決。
        
        本來項目是用Mybatis的,現在爲了這個事情,需要添加jpa的註解
        
        表是生成了,但是數據似乎還是需要插入,怎麼插入,可以用Mybatis或jpa的方式插入,其實也還是很麻煩
        

總結

對於單測,總結幾點

  1. 不要搞什麼h2,不實用。整理sql腳本生成表並插入數據,麻煩,而且後期還要維護表變更等。又不是直接Navicat導出表結構和數據的sql就能用,還得整理。

  2. 也不要搞什麼jpa反向工程生成表,且不說這種情況能不能順利生成表,初始化數據還是得老實寫,方便些可能還不如sql腳本導入

  3. 直接就使用共同的庫進行單測,這些情況這麼解決

    1. 刪除數據:加上@Translational,回滾。或者你要測試刪除,則自己先新增,再刪除

    2. 某個業務接口需要數據先存在,但是保證不了數據不被同事刪除:自己在測試中先新增,再查詢

    3. 依賴第三方接口:用mockito

    4. 其他的業務依賴:具體問題具體解決

      比如新增xxx,有業務要求xxx的name字段不能重複,我怎麼保證單測時插入的數據不重複?
      可以使用用隨機名字,要是隨機都重複了,那就認命。(你也可以較真,去數據庫先查一把所有name,然後鎖住表,再插入不重複的name)
      
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章