欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

java單元測(cè)試JUnit框架原理與用法實(shí)例教程

 更新時(shí)間:2017年11月09日 10:56:44   作者:維C果糖  
這篇文章主要介紹了java單元測(cè)試JUnit框架原理與用法,結(jié)合實(shí)例形式較為詳細(xì)的分析了java單元測(cè)試JUnit框架的概念、原理、使用方法及相關(guān)注意事項(xiàng),需要的朋友可以參考下

本文實(shí)例講述了java單元測(cè)試JUnit框架原理與用法。分享給大家供大家參考,具體如下:

1 簡(jiǎn)介

JUnit是一個(gè)Java語(yǔ)言的單元測(cè)試框架,它由 Kent Beck 和 Erich Gamma 建立,逐漸成為 xUnit 家族中最為成功的一個(gè)。 JUnit有它自己的JUnit擴(kuò)展生態(tài)圈,多數(shù)Java的開發(fā)環(huán)境都已經(jīng)集成了JUnit作為單元測(cè)試的工具。在這里,一個(gè)單元可以是一個(gè)方法、類、包或者子系統(tǒng)。因此,單元測(cè)試是指對(duì)代碼中的最小可測(cè)試單元進(jìn)行檢查和驗(yàn)證,以便確保它們正常工作。例如,我們可以給予一定的輸入測(cè)試輸出是否是所希望得到的結(jié)果。在本篇博客中,作者將著重介紹 JUnit 4.X 版本的特性,這也是我們?cè)谌粘i_發(fā)中使用最多的版本。

2 特點(diǎn)

JUnit提供了注釋以及確定的測(cè)試方法;
JUnit提供了斷言用于測(cè)試預(yù)期的結(jié)果;
JUnit測(cè)試優(yōu)雅簡(jiǎn)潔不需要花費(fèi)太多的時(shí)間;
JUnit測(cè)試讓大家可以更快地編寫代碼并且提高質(zhì)量;
JUnit測(cè)試可以組織成測(cè)試套件包含測(cè)試案例,甚至其他測(cè)試套件;
Junit顯示測(cè)試進(jìn)度,如果測(cè)試是沒有問題條形是綠色的,測(cè)試失敗則會(huì)變成紅色;
JUnit測(cè)試可以自動(dòng)運(yùn)行,檢查自己的結(jié)果,并提供即時(shí)反饋,沒有必要通過測(cè)試結(jié)果報(bào)告來手動(dòng)梳理。

3 內(nèi)容

3.1 注解

@Test :該注釋表示,用其附著的公共無效方法(即用public修飾的void類型的方法 )可以作為一個(gè)測(cè)試用例;
@Before :該注釋表示,用其附著的方法必須在類中的每個(gè)測(cè)試之前執(zhí)行,以便執(zhí)行測(cè)試某些必要的先決條件;
@BeforeClass :該注釋表示,用其附著的靜態(tài)方法必須執(zhí)行一次并在類的所有測(cè)試之前,發(fā)生這種情況時(shí)一般是測(cè)試計(jì)算共享配置方法,如連接到數(shù)據(jù)庫(kù);
@After :該注釋表示,用其附著的方法在執(zhí)行每項(xiàng)測(cè)試后執(zhí)行,如執(zhí)行每一個(gè)測(cè)試后重置某些變量,刪除臨時(shí)變量等;
@AfterClass :該注釋表示,當(dāng)需要執(zhí)行所有的測(cè)試在JUnit測(cè)試用例類后執(zhí)行,AfterClass注解可以使用以清理建立方法,如斷開數(shù)據(jù)庫(kù)連接,注意:附有此批注(類似于BeforeClass)的方法必須定義為靜態(tài);
@Ignore :該注釋表示,當(dāng)想暫時(shí)禁用特定的測(cè)試執(zhí)行可以使用忽略注釋,每個(gè)被注解為@Ignore的方法將不被執(zhí)行。

/**
* JUnit 注解示例
*/
@Test
public void testYeepay(){
  Syetem.out.println("用@Test標(biāo)示測(cè)試方法!");
}
@AfterClass
public static void paylus(){
  Syetem.out.println("用@AfterClass標(biāo)示的方法在測(cè)試用例類執(zhí)行完之后!");
}

3.2 斷言

在這里,作者將介紹一些斷言方法,所有這些方法都來自 org.junit.Assert 類,其擴(kuò)展了 java.lang.Object 類并為它們提供編寫測(cè)試,以便檢測(cè)故障。簡(jiǎn)而言之,我們就是通過斷言方法來判斷實(shí)際結(jié)果與我們預(yù)期的結(jié)果是否相同,如果相同,則測(cè)試成功,反之,則測(cè)試失敗。

void assertEquals([String message], expected value, actual value) :斷言兩個(gè)值相等,值的類型可以為int、short、long、byte、char 或者
java.lang.Object,其中第一個(gè)參數(shù)是一個(gè)可選的字符串消息;
void assertTrue([String message], boolean condition) :斷言一個(gè)條件為真;
void assertFalse([String message],boolean condition) :斷言一個(gè)條件為假;
void assertNotNull([String message], java.lang.Object object) :斷言一個(gè)對(duì)象不為空(null);
void assertNull([String message], java.lang.Object object) :斷言一個(gè)對(duì)象為空(null);
void assertSame([String message], java.lang.Object expected, java.lang.Object actual) :斷言兩個(gè)對(duì)象引用相同的對(duì)象;
void assertNotSame([String message], java.lang.Object unexpected, java.lang.Object actual) :斷言兩個(gè)對(duì)象不是引用同一個(gè)對(duì)象;
void assertArrayEquals([String message], expectedArray, resultArray) :斷言預(yù)期數(shù)組和結(jié)果數(shù)組相等,數(shù)組的類型可以為int、long、short、char、byte 或者 java.lang.Object

4 JUnit 3.X 和 JUnit 4.X 的區(qū)別

4.1 JUnit 3.X

(1)使用 JUnit 3.X 版本進(jìn)行單元測(cè)試時(shí),測(cè)試類必須要繼承于 TestCase 父類;
(2)測(cè)試方法需要遵循的原則:

① public的;
② void的;
③ 無方法參數(shù);
④方法名稱必須以 test 開頭;

(3)不同的測(cè)試用例之間一定要保持完全的獨(dú)立性,不能有任何的關(guān)聯(lián);
(4)要掌握好測(cè)試方法的順序,不能依賴于測(cè)試方法自己的執(zhí)行順序。

/**
* 用 JUnit 3.X 進(jìn)行測(cè)試
*/
import junit.framework.Assert;
import junit.framework.TestCase;
public class TestOperation extends TestCase {
  private Operation operation;
  public TestOperation(String name) { // 構(gòu)造函數(shù)
    super(name);
  }
  @Override
  public void setUp() throws Exception { // 在每個(gè)測(cè)試方法執(zhí)行 [之前] 都會(huì)被調(diào)用,多用于初始化
    System.out.println("歡迎使用Junit進(jìn)行單元測(cè)試...");
    operation = new Operation();
  }
  @Override
  public void tearDown() throws Exception { // 在每個(gè)測(cè)試方法執(zhí)行 [之后] 都會(huì)被調(diào)用,多用于釋放資源
    System.out.println("Junit單元測(cè)試結(jié)束...");
  }
  public void testDivideByZero() {
    Throwable te = null;
    try {
      operation.divide(6, 0);
      Assert.fail("測(cè)試失敗"); //斷言失敗
    } catch (Exception e) {
      e.printStackTrace();
      te = e;
    }
    Assert.assertEquals(Exception.class, te.getClass());
    Assert.assertEquals("除數(shù)不能為 0 ", te.getMessage());
  }
}

4.2 JUnit 4.X

(1)使用 JUnit 4.X 版本進(jìn)行單元測(cè)試時(shí),不用測(cè)試類繼承TestCase父類;
(2)JUnit 4.X 版本,引用了注解的方式進(jìn)行單元測(cè)試;
(3)JUnit 4.X 版本我們常用的注解包括:

@Before 注解:與JUnit 3.X 中的 setUp() 方法功能一樣,在每個(gè)測(cè)試方法之前執(zhí)行,多用于初始化;
@After 注解:與 JUnit 3.X 中的 tearDown() 方法功能一樣,在每個(gè)測(cè)試方法之后執(zhí)行,多用于釋放資源;
@Test(timeout = xxx) 注解:設(shè)置當(dāng)前測(cè)試方法在一定時(shí)間內(nèi)運(yùn)行完,否則返回錯(cuò)誤;
@Test(expected = Exception.class) 注解:設(shè)置被測(cè)試的方法是否有異常拋出。拋出異常類型為:Exception.class;

此外,我們可以通過閱讀上面的第二部分“2 注解”了解更多的注解。

/**
* 用 JUnit 4.X 進(jìn)行測(cè)試
*/
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
public class TestOperation {
  private Operation operation;
  @BeforeClass
  public static void globalInit() { // 在所有方法執(zhí)行之前執(zhí)行
    System.out.println("@BeforeClass標(biāo)注的方法,在所有方法執(zhí)行之前執(zhí)行...");
  }
  @AfterClass
  public static void globalDestory() { // 在所有方法執(zhí)行之后執(zhí)行
    System.out.println("@AfterClass標(biāo)注的方法,在所有方法執(zhí)行之后執(zhí)行...");
  }
  @Before
  public void setUp() { // 在每個(gè)測(cè)試方法之前執(zhí)行
    System.out.println("@Before標(biāo)注的方法,在每個(gè)測(cè)試方法之前執(zhí)行...");
    operation = new Operation();
  }
  @After
  public void tearDown() { // 在每個(gè)測(cè)試方法之后執(zhí)行
    System.out.println("@After標(biāo)注的方法,在每個(gè)測(cè)試方法之后執(zhí)行...");
  }
  @Test(timeout=600)
  public void testAdd() { // 設(shè)置限定測(cè)試方法的運(yùn)行時(shí)間 如果超出則返回錯(cuò)誤
    System.out.println("測(cè)試 add 方法...");
    int result = operation.add(2, 3);
    assertEquals(5, result);
  }
  @Test
  public void testSubtract() {
    System.out.println("測(cè)試 subtract 方法...");
    int result = operation.subtract(1, 2);
    assertEquals(-1, result);
  }
  @Test
  public void testMultiply() {
    System.out.println("測(cè)試 multiply 方法...");
    int result = operation.multiply(2, 3);
    assertEquals(6, result);
  }
  @Test
  public void testDivide() {
    System.out.println("測(cè)試 divide 方法...");
    int result = 0;
    try {
      result = operation.divide(6, 2);
    } catch (Exception e) {
      fail();
    }
    assertEquals(3, result);
  }
  @Test(expected = Exception.class)
  public void testDivideAgain() throws Exception {
    System.out.println("測(cè)試 divide 方法,除數(shù)為 0 的情況...");
    operation.divide(6, 0);
    fail("test Error");
  }
  public static void main(String[] args) {
  }
}

4.3 特別提醒

通過以上兩個(gè)例子,我們已經(jīng)可以大致知道 JUnit 3.X 和 JUnit 4.X 兩個(gè)版本的區(qū)別啦!首先,如果我們使用 JUnit 3.X,那么在我們寫的測(cè)試類的時(shí)候,一定要繼承 TestCase 類,但是如果我們使用 JUnit 4.X,則不需繼承 TestCase 類,直接使用注解就可以啦!在 JUnit 3.X 中,還強(qiáng)制要求測(cè)試方法的命名為“ testXxxx ”這種格式;在 JUnit 4.X 中,則不要求測(cè)試方法的命名格式,但作者還是建議測(cè)試方法統(tǒng)一命名為“ testXxxx ”這種格式,簡(jiǎn)潔明了。

此外,在上面的兩個(gè)示例中,我們只給出了測(cè)試類,但是在這之前,還應(yīng)該有一個(gè)被測(cè)試類,也就是我們真正要實(shí)現(xiàn)功能的類。現(xiàn)在,作者將給出上面示例中被測(cè)試的類,即 Operation 類:

/**
* 定義了加減乘除的法則
*/
public class Operation {
  public static void main(String[] args) {
    System.out.println("a + b = " + add(1,2));
    System.out.println("a - b = " + subtract(1,2));
    System.out.println("a * b = " + multiply(1,2));
    System.out.println("a / b = " + divide(4,2));
    System.out.println("a / b = " + divide(1,0));
  }
  public static int add(int a, int b) {
    return a + b;
  }
  public static int subtract(int a, int b) {
    return a - b;
  }
  public static int multiply(int a, int b) {
    return a * b;
  }
  public static int divide(int a, int b) {
    return a / b;
  }
}

5 測(cè)試示例

5.1 示例一:簡(jiǎn)單的 JUnit 3.X 測(cè)試

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import java.util.ArrayList;
import java.util.Collection;
/**
 * 1、創(chuàng)建一個(gè)測(cè)試類,繼承TestCase類
 */
public class SimpleTestDemo extends TestCase {
  public SimpleTestDemo(String name) {
    super(name);
  }
  /**
   * 2、寫一個(gè)測(cè)試方法,斷言期望的結(jié)果
   */
  public void testEmptyCollection(){
    Collection collection = new ArrayList();
    assertTrue(collection.isEmpty());
  }
  /**
   * 3、寫一個(gè)suite()方法,它會(huì)使用反射動(dòng)態(tài)的創(chuàng)建一個(gè)包含所有的testXxxx方法的測(cè)試套件
   */
  public static Test suit(){
    return new TestSuite(SimpleTestDemo.class);
  }
  /**
   * 4、寫一個(gè)main()方法,以文本運(yùn)行器的方式方便的運(yùn)行測(cè)試
   */
  public static void main(String[] args) {
    junit.textui.TestRunner.run(suit());
  }
}

5.2 示例二:套件測(cè)試

首先,介紹一下套件測(cè)試,簡(jiǎn)單來講,測(cè)試套件是指:一些測(cè)試不同類的用例,可以使用 @RunWith 和 @Suite 注解把所有的測(cè)試類套在一起,從而形成測(cè)試套件。如果有很多測(cè)試類,想讓它們都運(yùn)行在同一時(shí)間,而不是單一地運(yùn)行每個(gè)測(cè)試,套件測(cè)試是非常有用的。當(dāng)一個(gè)類被注解為 @RunWith, JUnit 將調(diào)用其中的注解,以便運(yùn)行測(cè)試類,而不使用內(nèi)置的 JUnit 運(yùn)行方法。

/**
* 待測(cè)試類
*/
import java.util.Arrays;
public class GotoWork {
  public String[] prepareSkills() {
    String[] skill = { "Java", "MySQL", "JSP" };
    System.out.println("My skills include : " + Arrays.toString(skill));
    return skill;
  }
  public String[] addSkills() {
    String[] skill = { "Java", "MySQL", "JSP", "JUnit" };
    System.out.println("Look, my skills include : " + Arrays.toString(skill));
    return skill;
  }
}

/**
* 測(cè)試類 1
*/
import org.junit.Test;
import static org.junit.Assert.*;
public class PrepareSkillsTest {
  GotoWork gotoWork = new GotoWork();
  String[] skill = { "Java", "MySQL", "JSP" };
  @Test
  public void testPrepareSkills() {
    System.out.println("Inside testPrepareSkills()");
    assertArrayEquals(skill, gotoWork.prepareSkills());
  }
}

/**
* 測(cè)試類 2
*/
import org.junit.Test;
import static org.junit.Assert.*;
public class AddSkillsTest {
  GotoWork gotoWork = new GotoWork();
  String[] skill = { "Java", "MySQL", "JSP", "JUnit" };
  @Test
  public void testAddSkills() {
    System.out.println("Inside testAddPencils()");
    assertArrayEquals(skill, gotoWork.addSkills());
  }
}

/**
* 套件測(cè)試
*/
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@RunWith(Suite.class)
@Suite.SuiteClasses({ PrepareSkillsTest.class, AddSkillsTest.class })
public class SuitTest {
}

使用 @Suite.SuiteClasses 注解,可以定義測(cè)試類,將被列入執(zhí)行,并且執(zhí)行的順序就是在 @Suite.SuiteClasses 注解中定義的順序。

5.3 示例三:參數(shù)化測(cè)試

首先介紹一下參數(shù)化測(cè)試,一個(gè)測(cè)試類可以被看作是一個(gè)參數(shù)化測(cè)試類,當(dāng)其滿足下列所有要求:

① 該類被注解為 @RunWith(Parameterized.class);
② 該類有一個(gè)構(gòu)造函數(shù),存儲(chǔ)測(cè)試數(shù)據(jù);
③ 該類有一個(gè)靜態(tài)方法生成并返回測(cè)試數(shù)據(jù),并標(biāo)注 @Parameters 注解;
④ 該類有一個(gè)測(cè)試方法,即用注解 @Test 標(biāo)注的方法。

/**
* 待測(cè)試類
*/
public class Calculate {
  public int sum(int var1, int var2) {
    System.out.println("此方法的參數(shù)值分別為 : " + var1 + " + " + var2);
    return var1 + var2;
  }
}

/**
* 參數(shù)化測(cè)試類
*/
import static org.junit.Assert.assertEquals;
import java.util.Arrays;
import java.util.Collection;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
public class CalculateTest {
  private int expected;
  private int first;
  private int second;
  public CalculateTest(int expectedResult, int firstNumber, int secondNumber) {
    this.expected = expectedResult;
    this.first = firstNumber;
    this.second = secondNumber;
  }
  @Parameters
  public static Collection addedNumbers() {
    return Arrays.asList(new Integer[][] { { 3, 1, 2 }, { 5, 2, 3 }, { 7, 3, 4 }, { 9, 4, 5 }, });
  }
  @Test
  public void testSum() {
    Calculate add = new Calculate();
    System.out.println("Addition with parameters : " + first + " and " + second);
    assertEquals(expected, add.sum(first, second));
  }
}

觀察 CalculateTest 類,它滿足上述所有的要求,因此它就可以稱為一個(gè)參數(shù)化測(cè)試類。addedNumbers 方法使用注釋 @Parameters 返回?cái)?shù)組的集合,每個(gè)數(shù)組包括每個(gè)測(cè)試執(zhí)行輸入和輸出數(shù)字,每個(gè)數(shù)組中的元素?cái)?shù)必須相同好與構(gòu)造參數(shù)的個(gè)數(shù)相匹配。所以,在這種特定的情況下,每個(gè)數(shù)組包括三個(gè)元素,即表示要加入的兩個(gè)元素和一個(gè)結(jié)果元素。

6 個(gè)人建議

有些童鞋可能會(huì)有一些誤解,認(rèn)為寫測(cè)試代碼沒有用,而且還會(huì)增大自己的壓力,浪費(fèi)時(shí)間。但事實(shí)上,寫測(cè)試代碼與否,還是有很大區(qū)別的,如果是在小的項(xiàng)目中,或許這種區(qū)別還不太明顯,但如果在大型項(xiàng)目中,一旦出現(xiàn)錯(cuò)誤或異常,用人力去排查的話,那將會(huì)浪費(fèi)很多時(shí)間,而且還不一定排查的出來,但是如果用測(cè)試代碼的話,JUnit 就是自動(dòng)幫我們判斷一些代碼的結(jié)果正確與否,從而節(jié)省的時(shí)間將會(huì)遠(yuǎn)遠(yuǎn)超過你寫測(cè)試代碼的時(shí)間。

因此,個(gè)人建議:要養(yǎng)成編寫測(cè)試代碼的習(xí)慣,碼一點(diǎn)、測(cè)一點(diǎn);再碼一點(diǎn),再測(cè)一點(diǎn),如此循環(huán)。在我們不斷編寫與測(cè)試代碼的過程中,我們將會(huì)對(duì)類的行為有一個(gè)更為深入的了解,從而可以有效的提高我們的工作效率。下面,作者就給出一些具體的編寫測(cè)試代碼的技巧和較好的實(shí)踐方法:

1. 不要用 TestCase 的構(gòu)造函數(shù)初始化 Fixture,而要用 setUp() 和 tearDown() 方法;
2. 不要依賴或假定測(cè)試運(yùn)行的順序,因?yàn)?JUnit 會(huì)利用 Vector 保存測(cè)試方法,所以不同的平臺(tái)會(huì)按不同的順序從 Vector 中取出測(cè)試方法;
3. 避免編寫有副作用的 TestCase,例如:如果隨后的測(cè)試依賴于某些特定的交易數(shù)據(jù),就不要提交交易數(shù)據(jù),只需要簡(jiǎn)單的回滾就可以了;
4. 當(dāng)繼承一個(gè)測(cè)試類時(shí),記得調(diào)用父類的 setUp() 和 tearDown() 方法;
5. 將測(cè)試代碼和工作代碼放在一起,同步編譯和更新;
6. 測(cè)試類和測(cè)試方法應(yīng)該有一致的命名方案,如在工作類名前加上 test 從而形成測(cè)試類名;
7. 確保測(cè)試與時(shí)間無關(guān),不要使用過期的數(shù)據(jù)進(jìn)行測(cè)試,以至于導(dǎo)致在隨后的維護(hù)過程中很難重現(xiàn)測(cè)試;
8. 如果編寫的軟件面向國(guó)際市場(chǎng),那么編寫測(cè)試時(shí)一定要考慮國(guó)際化的因素;
9. 盡可能地利用 JUnit 提供地 assert 和 fail 方法以及異常處理的方法,其可以使代碼更為簡(jiǎn)潔;
10. 測(cè)試要盡可能地小,執(zhí)行速度快;
11. 不要硬性規(guī)定數(shù)據(jù)文件的路徑;
12. 使用文檔生成器做測(cè)試文檔。

事實(shí)上,在 Junit 中使用 try catch 來捕獲異常是沒有必要的,因?yàn)?Junit 會(huì)自動(dòng)捕獲異常,那些沒有被捕獲的異常就會(huì)被當(dāng)成錯(cuò)誤處理啦!

更多關(guān)于java相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Java數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Java字符與字符串操作技巧總結(jié)》、《Java操作DOM節(jié)點(diǎn)技巧總結(jié)》、《Java文件與目錄操作技巧匯總》和《Java緩存操作技巧匯總

希望本文所述對(duì)大家java程序設(shè)計(jì)有所幫助。

相關(guān)文章

  • Spring事務(wù)相關(guān)問題解決方案

    Spring事務(wù)相關(guān)問題解決方案

    這篇文章主要介紹了Spring事務(wù)相關(guān)問題解決方案,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • Spring事務(wù)的開啟原理詳解

    Spring事務(wù)的開啟原理詳解

    這篇文章主要介紹了Spring事務(wù)的簡(jiǎn)單實(shí)現(xiàn)步驟,幫助大家更好的理解和學(xué)習(xí)使用spring,感興趣的朋友可以了解下
    2021-03-03
  • 單機(jī)redis分布式鎖實(shí)現(xiàn)原理解析

    單機(jī)redis分布式鎖實(shí)現(xiàn)原理解析

    這篇文章主要介紹了單機(jī)redis分布式鎖實(shí)現(xiàn)原理解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-04-04
  • Spring三種方法的注解自動(dòng)注入問題

    Spring三種方法的注解自動(dòng)注入問題

    這篇文章主要介紹了Spring三種方法的注解自動(dòng)注入問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • 最新評(píng)論