详解介绍JUnit单元测试框架(完整版)
(一)JUnit介紹
目錄
(一)JUnit介紹
1.什么是單元測試?
2.什么是單元測試框架?
3.什么是JUnit?
(二)JUnit 安裝
1.IntelliJ IDEA 安裝 Junit
2.Maven 安裝 Junit
(三)JUnit 編寫單元測試
1.編寫單元測試
2.測試功能模塊
(四)JUnit 注解
1.JUnit 注解
2.例子
(五)JUnit 注解之Fixture
什么是Fixture
JUnit 中的 Fixture
(六)JUnit 用例執行順序
@FixMethodOrder
例子
?(七)JUnit 斷言方法
JUnit 斷言方法
例子
(八)JUnit 測試批量運行
IntelliJ IDEA 中設置運行
通過測試套件運行
(九)JUnit5 介紹與安裝
JUnit5 介紹
Maven 安裝
(十)JUnit5 創建測試
創建測試用例
(十一)JUnit5 新的用法
(十二)補充:JUnit 注解之Rule
使用框架自帶的Rule
自定義的Rule
1.什么是單元測試?
單元測試負責對最小的軟件設計單元(模塊)進行驗證,根據軟件設計文檔中對模塊功能的描述,對重要的程序分支進行測試并發現錯誤。
2.什么是單元測試框架?
對于單元測試框架來講,它主要完成以下幾件事。
提供用例組織與執行:測試用例只有幾條時,可以不考慮用例組織,但是用例達到成百上千時,大量的測試用例堆砌在一起,就產生了擴展性與維護性等問題
提供豐富的斷言方法:不論是功能測試,還是單元測試,在用例執行完之后都需要將實際結果與預期結果相比較(斷言),從而斷定用例是否執行通過。單元測試框架一般提供豐富的斷言方法。例如:判斷相等/不等、包含/不包含、True/False的斷言方法等
提供豐富的日志:?當測試用例執行失敗時能拋出清晰的失敗原因,當所有用例執行完成后能提供豐富的執行結果。例如,總執行時間、失敗用例數、成功用例數等。
從這些特性來看單元測試框架的作用是:幫助我們更自動化完成測試,所以,它是自動化測試的基礎。
3.什么是JUnit?
Junit 官網:http://junit.org/
JUnit 是一個編寫可重復測試的簡單框架。它是單元測試框架的 xUnit 架構的一個實例。
(二)JUnit 安裝
Junit目前分兩個版本,Junit4 和 Junit5 , 本系列教程打算從 Junit4 開始介紹,最后,再介紹 Junit5 有哪些新特性
1.IntelliJ IDEA 安裝 Junit
Java 開發的同學,推薦使用 IntelliJ IDEA,推薦閱讀《IntelliJ IDEA 教程》。
1、下載?junit-4.12.jar?文件:https://github.com/junit-team/junit4/releases
2、 打開 IntelliJ IDEA ,菜單欄:File菜單 –> Porject Structure 選項 –> Dependencies 標簽 –> 點擊 “+” 號 –> Library… –> Java 。?選擇下載的?junit-4.12.jar?進行添加。
3、以同樣的方式下載和導入?hamcrest:?https://github.com/hamcrest/JavaHamcrest/releases?,否則,你將無法運行 Junit 單元測試。
2.Maven 安裝 Junit
相比較而言,Maven 的安裝要簡單很多,打開你 Maven 項目中的 pom.xml 文件,添加如下配置:
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope> </dependency>更多的 Maven 項目,可以登錄:https://www.mvnrepository.com?網站查找。
(三)JUnit 編寫單元測試
1.編寫單元測試
創建 JunitDemo 類,編寫第一個單元測試用例。
import static org.junit.Assert.assertEquals; import org.junit.Test;public class JunitDemo {@Testpublic void myFirstTest() {assertEquals(2+2, 4);}}@Test?用來注釋一個普通的方法為一條測試用例。
assertEquals()?方法用于斷言兩個值是否相關。
2.測試功能模塊
創建一個被測試類:Count ,代碼如下:
public class Count {/*** 計算并返回兩個參數的和*/public int add(int x ,int y){return x + y;} }Count 類的實現非常簡單,看注釋就可以了。
接下來,創建 CountTest 類,用于測試 Count 類。
import static org.junit.Assert.assertEquals; import org.junit.Test;public class CountTest {@Testpublic void testAdd() {Count count = new Count();int result = count.add(2,2);assertEquals(result, 4);}}new?出 Count 類,調用 add() 方法并傳參,通過 assertEquals() 斷言 返回結果。
恭喜! 你已經會編寫單元測試了。
(四)JUnit 注解
1.JUnit 注解
JUnit 注解說明:
| @Test: | 標識一條測試用例。 (A)?(expected=XXEception.class) ? (B)?(timeout=xxx) |
| @Ignore:? | 忽略的測試用例。 |
| @Before:? | 每一個測試方法之前運行。 |
| @After :? | 每一個測試方法之后運行。 |
| @BefreClass | ?所有測試開始之前運行。 |
| @AfterClass? | 所有測試結果之后運行。 |
2.例子
創建被測試類 Count .
public class Count {/*** 計算并返回兩個參數的和*/public int add(int x ,int y){return x + y;}/*** 計算并返回兩個數相除的結果*/public int division(int a, int b){return a / b;} }創建測試類 CountTest .
import static org.junit.Assert.assertEquals;import org.junit.Ignore; import org.junit.Test;public class CountTest {//驗證超時@Test(timeout=100)public void testAdd() throws InterruptedException {Thread.sleep(101);new Count().add(1, 1);}//驗證拋出異常@Test(expected=ArithmeticException.class)public void testDivision() {new Count().division(8, 0);}// 跳過該條用例@Ignore@Testpublic void testAdd2() {Count count = new Count();int result = count.add(2,2);assertEquals(result, 5);}}1、在 testAdd() 用例中設置?timeout=100?, 說明的用例的運行時間不能超過 100 毫秒, 但故意在用例添加 sleep() 方法休眠 101 毫秒,所以會導致用例失敗。
2、在 Java 中被除數不能為0,所以?8?0?會報 ArithmeticException 異常, 在 @Test 中設置?expected=ArithmeticException.class?,說明拋該異常符合預期。
3、@Ignore?表來標識該用例跳過,不管用例運行成功還是失敗。
執行結果如下:
(五)JUnit 注解之Fixture
繼續介紹 JUnit 的注解
什么是Fixture
Test Fixture 是指一個測試運行所需的固定環境,準確的定義:
The test fixture is everything we need to have in place to exercise the SUT
在進行測試時,我們通常需要把環境設置成已知狀態(如創建對象、獲取資源等)來創建測試,每次測試開始時都處于一個固定的初始狀態;測試結果后需要將測試狀態還原,所以,測試執行所需要的固定環境稱為 Test Fixture。
JUnit 中的 Fixture
被測試類同樣使用上一小節的 Count , 創建 TestFixture 測試類。
import static org.junit.Assert.*; import org.junit.*;public class TestFixture {//在當前測試類開始時運行。@BeforeClasspublic static void beforeClass(){System.out.println("-------------------beforeClass");}//在當前測試類結束時運行。@AfterClasspublic static void afterClass(){System.out.println("-------------------afterClass");}//每個測試方法運行之前運行@Beforepublic void before(){System.out.println("=====before");}//每個測試方法運行之后運行@Afterpublic void after(){System.out.println("=====after");}@Testpublic void testAdd1() {int result=new Count().add(5,3);assertEquals(8,result);System.out.println("test Run testadd1");}@Testpublic void testAdd2() {int result=new Count().add(15,13);assertEquals(28,result);System.out.println("test Run testadd2");}}代碼中的注釋已經對?@BeforeClass、 @AfterClass 、 @Before 、 @After?做了說明。
至于什么時候會用到這些方法跟你具體的業務用例有關,如果是 Web UI 自動化測試,可以把 瀏覽器驅動的定義放到?@Before中,瀏覽器的關閉放到?@After?中。
運行結果如下:
(六)JUnit 用例執行順序
在運行測試的過程中,有時候需要控制用例的執行順序。
@FixMethodOrder
JUnit 通過?@FixMethodOrder?注解來控制測試方法的執行順序的。@FixMethodOrder?注解的參數是?org.junit.runners.MethodSorters?對象,在枚舉類?org.junit.runners.MethodSorters?中定義了如下三種順序類型:
- MethodSorters.JVM
?Leaves the test methods in the order returned by the JVM. Note that the order from the JVM may vary from run to run (按照JVM得到的方法順序,也就是代碼中定義的方法順序)
- MethodSorters.DEFAULT(默認的順序)
Sorts the test methods in a deterministic, but not predictable, order() (以確定但不可預期的順序執行)
- MethodSorters.NAME_ASCENDING
Sorts the test methods by the method name, in lexicographic order, with Method.toString() used as a tiebreaker (按方法名字母順序執行)
例子
具體如何使用,看例子,創建 TestRunSequence 測試類。
import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runners.MethodSorters; import static org.junit.Assert.assertEquals;// 按字母順序執行 @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class TestRunSequence {@Testpublic void TestCase1() {assertEquals(2+2, 4);}@Testpublic void TestCase2() {assertEquals(2+2, 4);}@Testpublic void TestAa() {assertEquals("hello", "hi");} }MethodSorters.NAME_ASCENDING?設置按字母的順序執行,所以,TestAa()?先被執行,雖然它在代碼中是最后一條用例。
運行結果如下:
?(七)JUnit 斷言方法
JUnit 斷言方法
JUnit 所提供的斷言方法:
| assertArrayEquals(expecteds, actuals) | 查看兩個數組是否相等。 |
| assertEquals(expected, actual) | 查看兩個對象是否相等。類似于字符串比較使用的equals()方法。 |
| assertNotEquals(first, second) | 查看兩個對象是否不相等。 |
| assertNull(object) | 查看對象是否為空。 |
| assertNotNull(object) | 查看對象是否不為空。 |
| assertSame(expected, actual) | 查看兩個對象的引用是否相等。類似于使用“==”比較兩個對象。 |
| assertNotSame(unexpected, actual) | 查看兩個對象的引用是否不相等。類似于使用“!=”比較兩個對象。 |
| assertTrue(condition) | 查看運行結果是否為true。 |
| assertFalse(condition) | 查看運行結果是否為false。 |
| assertThat(actual, matcher) | 查看實際值是否滿足指定的條件。 |
| fail() | 讓測試失敗。 |
例子
關于斷言方法,我們前面用得最多的是?assertEquals?,用于斷言兩個對象是否相等。這里再介紹一個?assertTrue?的使用。
創建 AssertTest 測試類(包了含被測試方法):
import org.junit.*; import static org.junit.Assert.*;public class AssertTest {/*** 判斷一個數是否為素數*/public static Boolean Prime(int n) {for (int i = 2; i < Math.sqrt(n); i++) {if (n % i == 0) {return false;}}return true;}@Testpublic void testPrime(){int n = 7;assertTrue(AssertTest.Prime(n));}}Prime()?方法用于判斷一個數是否為素數(只能被1和它本身整除的數),并返回 True 或 False ,在測試用例中通過?assertTrue來斷言結果。
(八)JUnit 測試批量運行
前面測試用例的運行 主要針對單個測試類進行的,當然,在 IntelliJ IDEA 中也可以選擇單個的方法執行。那如果我們想運行所有的用例的文件呢?
IntelliJ IDEA 中設置運行
設置
在 IntelliJ IDEA 中,菜單欄:Run菜單 –> Edit Configurations…選項。
在 Junit 目錄下,選擇任意一個用例文件。
- Test Kind : 選擇用例的運行類型/級別。
- packages : 選擇用例運行的目錄,即你的測試用例目錄。
設置完成后,點擊?“OK”?按鈕。
運行
點擊 IntelliJ IDEA 工具欄上的運行按鈕,來運行 test 目錄下的所有用例。
運行結果:
通過測試套件運行
這種方法引入一種?“測試套件”?的概念,JUnit 提供了一種批量運行測試類的方法,叫測試套件。
測試套件的寫法需要遵循以下原則:
創建一個空類作為測試套件的入口;
使用注解?org.junit.runner.RunWith?和?org.junit.runners.Suite.SuitClasses?修飾這個空類。
將?org.junit.runners.Suite?作為參數傳入給注解?RunWith,以提示 JUnit 為此類測試使用套件運行器執行。
將需要放入此測試套件的測試類組成數組作為注解 SuiteClasses 的參數。
保證這個空類使用public修飾,而且存在公開的不帶任何參數的構造函數。
單獨創建一個測試類 runAllTest .
package test;import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses;@RunWith(Suite.class) @SuiteClasses({CountTest.class,TestFixture.class,AssertTest.class,TestRunSequence.class, }) public class runAllTest {}把需要運行的測試類放到?SuiteClasses?中,運行 runAllTest 測試類,即可批量執行測試用例。
(九)JUnit5 介紹與安裝
官方網址:http://junit.org/junit5/
Junit5 已經不算是新的版本了,2016 年推出非正式版,相比較 JUnit4 安裝和使用都有一定的差異。
JUnit5 介紹
The new major version of the programmer-friendly testing framework for Java 8
一個新的重要版本,程序員更友好的測試框架,基于 Java8。
關于
JUnit5 是 JUnit 的下一代。我們的目標是為 JVM 上的開發人員端測試創建一個最新的基礎。這包括針對 Java 8 及以上,以及使許多不同風格的測試。
Junit5 組成
先看來個公式:
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
這看上去比 Junit4 復雜,實際上在導入包時也會復雜一些。
-
JUnit Platform 是在JVM上啟動測試框架的基礎。
-
JUnit Jupiter 是JUnit5擴展的新的編程模型和擴展模型,用來編寫測試用例。Jupiter子項目為在平臺上運行Jupiter的測試提供了一個TestEngine (測試引擎)。
-
JUnit Vintage 提供了一個在平臺上運行 JUnit3 和 JUnit4 的 TestEngine 。
Maven 安裝
首先,你需要通過 IntelliJ?IDEA 創建一個 Maven 項目,IntelliJ?IDEA 集成的有 Maven,所以,你很容易做到這一點。通過 Maven 的 pom.xml 文件,添加 Junit5 。
pom.xml 文件配置如下:
<dependencies><dependency><groupId>org.junit.platform</groupId><artifactId>junit-platform-launcher</artifactId><version>1.0.1</version><scope>test</scope></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-engine</artifactId><version>5.0.1</version><scope>test</scope></dependency><dependency><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId><version>4.12.1</version><scope>test</scope></dependency></dependencies>(十)JUnit5 創建測試
創建測試用例
我在 IntelliJ?IDEA 中創建的 Maven 項目,目錄結構如下:
在 test.java 目錄下創建一個 FistJUnit5Tests 類。代碼如下:
import static org.junit.jupiter.api.Assertions.assertEquals;import org.junit.jupiter.api.Test;class FirstJUnit5Tests {@Testvoid myFirstTest() {assertEquals(2, 1 + 1);}}明顯看出和 Junit4 還是有些不同的。
首先,導入測試測試注解(@Test)和斷言方法(assertEquals)的路徑不同。
其次,不需要手動把測試和測試方法聲明為 public 了。
(十一)JUnit5 新的用法
創建 JUnit5NewTests 測試類。
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertAll;import org.junit.jupiter.api.*;class JUnit5NewTests {@BeforeEach@DisplayName("每條用例開始時執行")void start(){}@AfterEach@DisplayName("每條用例結束時執行")void end(){}@Testvoid myFirstTest() {assertEquals(2, 1 + 1);}@Test@DisplayName("描述測試用例╯°□°)╯")void testWithDisplayName() {}@Test@Disabled("這條用例暫時跑不過,忽略!")void myFailTest(){assertEquals(1,2);}@Test@DisplayName("運行一組斷言")public void assertAllCase() {assertAll("groupAssert",() -> assertEquals(2, 1 + 1),() -> assertTrue(1 > 0));}@Test@DisplayName("依賴注入1")public void testInfo(final TestInfo testInfo) {System.out.println(testInfo.getDisplayName());}@Test@DisplayName("依賴注入2")public void testReporter(final TestReporter testReporter) {testReporter.publishEntry("name", "Alex");}}用法都已經通過測試用例的?@DisplayName?進行了說明,這里不再解釋。
運行結果如下:
(十二)補充:JUnit 注解之Rule
一個JUnit Rule就是一個實現了TestRule的類,這些類的作用類似于?@Before、@After,是用來在每個測試方法的執行前后執行一些代碼的一個方法。 那為什么不直接用這些?@Before、@After呢?這是因為它們都只能作用于一個類,如果同一個setup需要在兩個類里面同時使用,那么你就要在兩個測試類里面定義相同的@Before方法,然后里面寫相同的代碼,這就造成了代碼重復。
此外,JUnit Rule還能做一些?@Before、@After這些注解做不到的事情,那就是他們可以動態的獲取將要運行的測試類、測試方法的信息。
使用框架自帶的Rule
除了增加Rule特性,新版JUnit還添加了很多核心Rule
- TemporaryFolder:測試可以創建文件與目錄并且會在測試運行結束后將其刪除。這對于那些與文件系統打交道且獨立運行的測試來說很有用。
- ExternalResource:這是一種資源使用模式,它會提前建立好資源并且會在測試結束后將其銷毀。這對于那些使用socket、嵌入式服務器等資源的測試來說很有用。
- ErrorCollector:可以讓測試在失敗后繼續運行并在測試結束時報告所有錯誤。這對于那些需要驗證大量獨立條件的測試來說很有用(盡管這本身可能是個“test smell”)。
- ExpectedException:可以在測試中指定期望的異常類型與消息。
- Timeout:為類中的所有測試應用相同的超時時間。
例如,TimeOut這個Rule的使用。
import org.junit.Rule; import org.junit.Test; import org.junit.rules.Timeout;public class RuleTestDemo {//使用Timeout這個Rule@Rulepublic Timeout timeout = new Timeout(1000); @Testpublic void testMethod1() throws Exception {Thread.sleep(1001);}@Testpublic void testMethod2() throws Exception {Thread.sleep(999);} }使用JUnit所提供的Timeout類,該類用于控制測試用例的執行超時時間。這里設置為1秒,當用例執行超過1秒則失敗。接下來分別在 testMethod1和testMethod2兩個用例中使用sleep()方法來控制用例的執行時間,顯然testMethod1超過1秒,則運行失敗。
自定義的Rule
除了可以使用JUnit框架自帶的Rule,還可以根據自己的需求自定義Rule。簡單來說,自定義一個Rule就是implement一個TestRule?接口,并實現apply()方法。該方法需要返回一個Statement對象。例子如下:
import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.Statement;public class MethodNameRule implements TestRule {public Statement apply(final Statement base, final Description description) {return new Statement() {@Overridepublic void evaluate() throws Throwable {//在測試方法運行之前做一些事情,在base.evaluate()之前String className = description.getClassName();String methodName = description.getMethodName();base.evaluate(); //運行測試方法//在測試方法運行之后做一些事情,在base.evaluate()之后System.out.println("Class name:"+className+", method name: "+methodName);}};} }這里實現的功能是在每次測試用例運行之后,打印當前測試用例的類名和方法名。 在上面的例子中添加這里定義的MethodNameRule 。
…… public class RuleTestDemo {//使用Timeout這個Rule@Rulepublic Timeout timeout = new Timeout(1000); //使用自定義Rule,@Rulepublic MethodNameRule methodNameRule = new MethodNameRule();……再次運行測試用例,執行結果如下:
?
總結
以上是生活随笔為你收集整理的详解介绍JUnit单元测试框架(完整版)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ubuntu10的pci扩展卡驱动安装失
- 下一篇: 手写原笔迹输入_原笔迹手写软件 - 随意