小夥伴們好呀,沖沖沖!!😝
本期帶來了一個奇怪的bug~和它帶來的一系列問題,讓我們一起往下看看叭!
!!! JUnit version 3.8 or later expected:
如下所示,當我在進行單元測試時,控制台居然抛出了這麼詭異的bug!
三個感歎号開頭
此刻的我 ???
異常資訊如下:
java.lang.ClassNotFoundException: junit.framework.ComparisonFailure
那麼先挖到它的源碼看個究竟叭 😝
在264行打個斷點,然後debug運作起來
通過
Alt+F8
來擷取這個類加載器 都使用到了哪些類
ClassLoader.getClassLoader(caller)
效果如下:可以看到這裡
至于為啥會點開這裡,主要時因為它比較突出 哈哈~
可以發現它加載了idea 插件目錄
IntelliJ IDEA 2020.1\plugins\junit\lib
中的
junit-rt.jar
檔案
猶豫了下,還是繼續探究下去 哈哈
奇怪的參數
于是我就一路 debug 下來,最後看到這個東東, 運作了
JUnitStarter
的
main
函數~
同時傳遞了三個變量
- -ideVersion5
- -junit3
- com.java4ye.demo.A,contextLoads (類,測試方法)
如圖~
這裡我們把這個
junit-rt.jar
解壓到上面的這個
junit-rt
目錄,
用
IDEA
打開 很快就可以找到這個
JUnitStarter
了。
!!!的來源
查閱代碼,發下有這麼一個調用邏輯~
if (!"com.intellij.junit5.JUnit5IdeaTestRunner".equals(agentName) && !canWorkWithJUnitVersion(System.err, agentName)) {
System.exit(-3);
}
Soga , 這個
Process finished with exit code -3
是這麼來的
canWorkWithJUnitVersion
junitVersionChecks
小結
可以發現如果代理名稱
agentName
不是
com.intellij.junit5.JUnit5IdeaTestRunner
就會去 check 這個
junit
版本。 然後去加載這個
junit.framework.ComparisonFailure
類。
tip:
Junit5
中并沒有這個類,版本 5 的架構更複雜,JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
順帶提下這個
ComparisonFailure
的作用:
當斷言equals for Strings失敗時抛出
如下 ε=ε=ε=( ̄▽ ̄) 居然還有郵箱 📫
為何會出現 Junit3
這個奇怪的參數
Junit3
這裡先解釋下,傳遞的參數乎關系到這個
agentName
那麼問題來了!
在我的 demo 中,使用的
Springboot
版本是
2.4.5
,同時在
pom
檔案中引入了
spring-boot-starter-test
,它的版本号是5.7 ,如下
可以看到明明使用的是
JUnit5
呀
帶着疑問來看看項目的結構是啥樣子叭~
嘿嘿,可以發現這裡
test
目錄下 和
main
目錄中有個 同包同名的類
A
test
下的
A
package com.java4ye.demo;
//import org.junit.Test;
import org.junit.jupiter.api.Test;
public class A{
@Test
public void contextLoads() {
System.out.println("hello");
}
}
這時我嘗試着将這個
test
下的
A
重命名為
AA
,奇怪的是,它正常跑起來了,哈哈,而且确實是用的
Junit5
于是我又做了一個實驗,導入
Junit4
的包,将
AA
改為
A
,繼續測試,結果也是正常的
小結
使用
Junit5
時,如果測試目錄
test
下的測試類和
main
目錄下的同包同名,會出現這個奇怪的參數
-Junit3
, 導緻抛出異常
!!! JUnit version 3.8 or later expected:
這裡我也很好奇為啥參數變成了
-Junit3
,可是不懂要怎麼
debug
看下了,無奈作罷 🐖
插曲
java.lang.NoClassDefFoundError:
在找到這個
JUnitStarter
類時, 4ye 嘗試着用指令
java JUnitStarter
去運作,結果居然抛出了
java.lang.NoClassDefFoundError:
java JUnitStarter
指令去運作,結果居然抛出了
java.lang.NoClassDefFoundError:
差別
不知道小夥伴們對這個
Error
熟不熟悉 哈哈,平時看到的都是
ClassNotFoundException
這兩者最大的差別就是:
一個是
Error
,一個是
Exception
哈哈
詳細點點說:
ClassNotFoundException
是非運作時異常,在編譯期間就檢測出來可能會發生的異常,需要你
try catch
的
而這個
java.lang.NoClassDefFoundError:
是屬于
error
,是
JVM
處理不了的錯誤。
這裡還有一點點小細節~
就是這個原因是在
JDK11
下才顯示出來的,之前用
JDK8
隻有錯誤一行~ 小夥伴們可以自己嘗試下
解決辦法
咳咳,那這個 錯誤 怎麼解決呢 ?
其實這個也是最原始的解決辦法 哈哈
可以在上面
IDEA
中反編譯出來的代碼看到我們這個
JUnitStarter
是屬于
package com.intellij.rt.junit;
包的 。
那麼我們正确的運作方式就是跑到
com
的同級目錄下去運作 ,如下~
注意這裡運作時要帶上包名(先不帶上那三個參數試試~)
java com.intellij.rt.junit.JUnitStarter
可以看到這裡已經出現了
!!! JUnit version 3.8 or later expected
也就是我們文章最開始的那段異常資訊了!
後面手動将需要的包放到這個目錄下,也可以正常運作啦~
其他小實驗和感悟就寫在下面的總結裡啦~
總結
一. 單元測試的命名要規範!
二. 不要引入不同版本的單元測試包
如果項目中使用到這個
Junit5
,此時又直接根據上面
!!! JUnit version 3.8 or later expected
這個異常,引入
Junit4
, 會出現新的異常
java.lang.Exception: No runnable methods
,此時需要你将
@Test
注解修改為
junit4
的版本~ 🐷
三. 擴充包解惑
比如我在
pom
檔案中引入了這個
spring-boot-starter-test
,此時它會幫我導入相應版本的
junit
包 ,而我也不知道它引入了什麼版本的測試包,這時可以在 IDEA 的擴充包中搜尋~,就可以查找到
junit
的版本了~
四. junit3 是使用繼承的方式, Junit4 開始才使用注解的形式
是以,如果你想試試繼承的寫法的話✍,可以試試 哈哈
五. 單元測試很重要,主要是為了證明你的邏輯在這個測試範圍是對的😝
我是4ye,我們下期再見啦,ヾ( ̄▽ ̄)ByeBye
歡迎關注,交個朋友呀!! ( •̀ ω •́ )y
作者簡介 :Java4ye ,很高興認識你!!😝
公衆号: Java4ye 部落客滴個人公衆号~ ,嘿嘿 喜歡就支援下啦 😋
讓我們開始這一場意外的相遇吧!~
歡迎留言!謝謝支援!ヾ(≧▽≦*)o