【Java单元测试】如何进行单元测试、异常测试、参数化测试、超时测试、测试多线程
Junit單元測試的步驟
(1)新建一個單元測試
(2)選擇位置
(3)選擇需要測試的方法
(4)是否將Junit 4添加到ClassPath中
(5)自動生成的測試類
(6) 然后就可以編寫單元測試了
單元測試的編寫
(1)Assert斷言
package cn.hanquan.junit;import static org.junit.jupiter.api.Assertions.*;import org.junit.jupiter.api.Test;class CalcTest {@Testvoid testAdd() {assertEquals(3, new Calc().add(1, 2));assertEquals(30, new Calc().add(10, 20));assertEquals(159, new Calc().add(150, 9));} }(2)Junit Fixture:Junit4 @Before、@After的使用
初始化測試資源稱為Fixture
@Before:創建初始化對象,在執行所有每一個@Test之前都會執行一次。如is = new FileInputStream()
@After:銷毀@Before創建的測試對象,在執行所有每一個@Test之后都會執行一次。如is.close()
@BeforeClass:在其中初始化非常耗時的對象,如:數據庫的連接
@AfterClass:清理@BeforeClass創建的資源,比如:斷開數據庫連接
注意:在JUnit5中,@Before @After 注解不執行
官方文檔:https://junit.org/junit5/docs/current/user-guide/#migrating-from-junit4-tips
@Before 和@After 被 @BeforeEach 和@AfterEach給替代了。
還有一些其他的的注解也被替代了。
在JUnit5的環境下寫了@Before @After , 講道理 IDE應該提醒 該注解已經不存在, 然而Eclipse并沒有這樣的提示。
代碼示例
被測試的類Calc.java
package cn.hanquan.junit;public class Calc {public Calc() {}public int add(int a, int b) {System.out.println(a + "+" + b + "=" + (a + b));return a + b;} }測試類CalcTest
package cn.hanquan.junit;import static org.junit.Assert.assertEquals;import org.junit.After; import org.junit.Before; import org.junit.Test;public class CalcTest {Calc c;@Beforepublic void initialize() {System.out.println(">>>>>>> initializing >>>>>>>");c = new Calc();}@Testpublic void testAdd1() {assertEquals(3, c.add(1, 2));assertEquals(30, c.add(10, 20));assertEquals(159, c.add(150, 9));}@Testpublic void testAdd2() {assertEquals(4, c.add(2, 2));assertEquals(36, c.add(13, 23));assertEquals(1000, c.add(-3000, 4000));}@Afterpublic void destroy() {System.out.println("<<<<<<<<< cleaning <<<<<<<<<\n");} }測試結果
輸出
(3)測試拋出的異常是否符合預期
package cn.hanquan.junit;import static org.junit.Assert.assertEquals;import org.junit.After; import org.junit.Before; import org.junit.Test;public class CalcTest {Calc c;@Beforepublic void initialize() {System.out.println(">>>>>>> initializing >>>>>>>");c = new Calc();}@Test // 測試輸出是否符合預期public void testAdd2() {assertEquals(20, c.divide(100, 5));}@Test(expected = ArithmeticException.class) // 針對異常進行的測試public void testAdd3() {c.divide(8, 0);}@Afterpublic void destroy() {System.out.println("<<<<<<<<< cleaning <<<<<<<<<\n");} }(4)參數化測試:一次運行多個測試
JUnit參數化測試的五個步驟:
(1)為準備使用參數化測試的測試類指定特殊的運行器 org.junit.runners.Parameterized
(2)為測試類聲明幾個變量,分別用于存放期望值和測試所用數據
(3)為測試類聲明一個帶有參數的公共構造函數,并在其中為第二個環節中聲明的幾個變量賦值
(4)為測試類聲明一個使用注解 org.junit.runners.Parameterized.Parameters 修飾的,返回值為 java.util.Collection 的公共靜態方法,并在此方法中初始化所有需要測試的參數對
(5)編寫測試方法,使用定義的變量作為參數進行測試。
示例代碼
package cn.hanquan.junit;import static org.junit.Assert.assertEquals;import java.util.Arrays; import java.util.Collection;import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters;/*** 使用Junit進行參數化測試的步驟* * @author Buuug**/ //(1)測試類指定特殊的運行器org.junit.runners.Parameterized @RunWith(Parameterized.class) public class CalcTest {Calc c;@Beforepublic void bef() {System.out.println("Before");c = new Calc();}// (2)為測試類聲明幾個變量,分別用于存放期望值和測試所用數據。此處我只放了測試所有數據,沒放期望值。private int n1;private int n2;private int result;// (3)為測試類聲明一個帶有參數的公共構造函數,并在其中為第二個環節中聲明的幾個變量賦值。public CalcTest(int n1, int n2, int result) {super();this.n1 = n1;this.n2 = n2;this.result = result;}// (4)為測試類聲明一個使用注解 org.junit.runners.Parameterized.Parameters 修飾的,返回值為// java.util.Collection 的公共靜態方法,并在此方法中初始化所有需要測試的參數對。@Parameterspublic static Collection<Object[]> data() {return Arrays.asList(new Object[][] { { 4, 2, 2 }, { 9, 3, 3 }, { -100, 25, -4 }, { 88, 2, 44 }, { 25, 5, 5 },{ 72, 8, 9 }, { 42, 6, 7 }, { 1, 1, 1 }, { 1000000, 333333, 888888 }, { 56, 8, 7 }, { 55, 55, 1 },{ 12, 6, 2 }, { 21, 10, 2 }, { 70, 20, 3 }, { 45, 15, 3 }, { 46, 15, 3 }, { 47, 3, 15 }, { 2, 1, 2 } });}// (5)步驟五:編寫測試方法,使用定義的變量作為參數進行測試。@Testpublic void testAdd() {assertEquals(result, c.divide(n1, n2));}@Afterpublic void aft() {System.out.println("After\n");} }測試結果
第8個未通過,是故意寫錯的。
(5)超時測試:設定運行時間限制,測試是否運行時間過長
在50行加一個@Test(timeout = 1)就行了。
一開始想通過Thread.sleep(1000);這種形式拖延時間,但是拋出了ThreadInterrupted異常,(沒有具體去了解原因),然后我又在@Test的方法里加了一個Lambda表達式開啟的多線程,結果開啟之后,不管sleep多長也沒有影響了,都可以在限定時間內結束,我尋思著是不是要join一下才可以。(后來加了Join,確實如此。)
我在被測試的類上面加了一些無用的循環拖延時間,然后把時間限定設置為1ms。看看效果吧:
示例代碼1:沒有使用多線程,只是加了沒用的循環拖延時間
package cn.hanquan.junit;import static org.junit.Assert.assertEquals;import java.util.Arrays; import java.util.Collection;import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters;/*** 使用Junit進行參數化測試的步驟* * @author Buuug**/ @RunWith(Parameterized.class) public class CalcTest {Calc c;@Beforepublic void bef() {System.out.println("Before");c = new Calc();}private int n1;private int n2;private int result;public CalcTest(int n1, int n2, int result) {super();this.n1 = n1;this.n2 = n2;this.result = result;}@Parameterspublic static Collection<Object[]> data() {return Arrays.asList(new Object[][] { { 4, 2, 2 }, { 9, 3, 3 }, { -100, 25, -4 }, { 88, 2, 44 }, { 25, 5, 5 },{ 72, 8, 9 }, { 42, 6, 7 }, { 1, 1, 1 }, { 1000000, 333333, 888888 }, { 56, 8, 7 }, { 55, 55, 1 },{ 12, 6, 2 }, { 21, 10, 2 }, { 70, 20, 3 }, { 45, 15, 3 }, { 46, 15, 3 }, { 47, 3, 15 }, { 2, 1, 2 } });}@Test(timeout = 1) // 設置超時時間public void testAdd() {assertEquals(result, c.divide(n1, n2));}@Afterpublic void aft() {System.out.println("After\n");} }測試結果
示例代碼2:使用多線程sleep模擬運行耗時,記得join一下主線程,否則都來不及計算就完成了
- CalcTest.java單元測試:時間限制為501ms。
- 被測試的類:Calc,里面Thread.sleep(500);。由于時間限制為501ms,因此僅空余出1ms給它做計算。
運行結果:部分未通過
那個拋出java.lang.InterruptedException異常的,是因為沒有在限制時間內運行完畢,被打斷了吧?(待解決,暫時沒有深入研究)
總結
以上是生活随笔為你收集整理的【Java单元测试】如何进行单元测试、异常测试、参数化测试、超时测试、测试多线程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【区块链:超级账本】Win10 Hype
- 下一篇: 【Java基础】Java中的值传递、引用