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

java程序員如何編寫更好的單元測試的7個技巧

 更新時間:2017年03月07日 10:11:03   作者:落葉的博客  
測試是開發(fā)的一個非常重要的方面,可以在很大程度上決定一個應用程序的命運。良好的測試可以在早期捕獲導致應用程序崩潰的問題,但較差的測試往往總是導致故障和停機。本文主要介紹java程序員編寫更好的單元測試的7個技巧。下面跟著小編一起來看下吧

測試是開發(fā)的一個非常重要的方面,可以在很大程度上決定一個應用程序的命運。良好的測試可以在早期捕獲導致應用程序崩潰的問題,但較差的測試往往總是導致故障和停機。

雖然有三種主要類型的軟件測試:單元測試,功能測試和集成測試,但是在這篇博文中,我們將討論開發(fā)人員級單元測試。在我深入講述具體細節(jié)之前,讓我們先來回顧一下這三種測試的詳細內(nèi)容。

一.軟件開發(fā)測試的類型

單元測試用于測試各個代碼組件,并確保代碼按照預期的方式工作。單元測試由開發(fā)人員編寫和執(zhí)行。大多數(shù)情況下,使用JUnit或TestNG之類的測試框架。測試用例通常是在方法級別寫入并通過自動化執(zhí)行。

集成測試檢查系統(tǒng)是否作為一個整體而工作。集成測試也由開發(fā)人員完成,但不是測試單個組件,而是旨在跨組件測試。系統(tǒng)由許多單獨的組件組成,如代碼,數(shù)據(jù)庫,Web服務器等。集成測試能夠發(fā)現(xiàn)如組件布線,網(wǎng)絡訪問,數(shù)據(jù)庫問題等問題。

功能測試通過將給定輸入的結果與規(guī)范進行比較來檢查每個功能是否正確實現(xiàn)。通常,這不是在開發(fā)人員級別的。功能測試由單獨的測試團隊執(zhí)行。測試用例基于規(guī)范編寫,并且實際結果與預期結果進行比較。有若干工具可用于自動化的功能測試,如Selenium和QTP。

如前所述,單元測試可幫助開發(fā)人員確定代碼是否正常工作。在這篇博文中,我將提供在Java中單元測試的有用提示。

二.使用框架來用于單元測試

Java提供了若干用于單元測試的框架。TestNG和JUnit是最流行的測試框架。JUnit和TestNG的一些重要功能:

  1. 易于設置和運行。

  2. 支持注釋。

  3. 允許忽略或分組并一起執(zhí)行某些測試。

  4. 支持參數(shù)化測試,即通過在運行時指定不同的值來運行單元測試。

  5. 通過與構建工具,如Ant,Maven和Gradle集成來支持自動化的測試執(zhí)行。

EasyMock是一個模擬框架,是單元測試框架,如JUnit和TestNG的補充。EasyMock本身不是一個完整的框架。它只是添加了創(chuàng)建模擬對象以便于測試的能力。例如,我們想要測試的一個方法可以調(diào)用從數(shù)據(jù)庫獲取數(shù)據(jù)的DAO類。在這種情況下,EasyMock可用于創(chuàng)建返回硬編碼數(shù)據(jù)的MockDAO。這使我們能夠輕松地測試我們意向的方法,而不必擔心數(shù)據(jù)庫訪問。

三.謹慎使用測試驅(qū)動開發(fā)

測試驅(qū)動開發(fā)(TDD)是一個軟件開發(fā)過程,在這過程中,在開始任何編碼之前,我們基于需求來編寫測試。由于還沒有編碼,測試最初會失敗。然后寫入最小量的代碼以通過測試。然后重構代碼,直到被優(yōu)化。

目標是編寫覆蓋所有需求的測試,而不是一開始就寫代碼,卻可能甚至都不能滿足需求。TDD是偉大的,因為它導致簡單的模塊化代碼,且易于維護??傮w開發(fā)速度加快,容易發(fā)現(xiàn)缺陷。此外,單元測試被創(chuàng)建作為TDD方法的副產(chǎn)品。

然而,TDD可能不適合所有的情況。在設計復雜的項目中,專注于最簡單的設計以便于通過測試用例,而不提前思考可能會導致巨大的代碼更改。此外,TDD方法難以用于與遺留系統(tǒng),GUI應用程序或與數(shù)據(jù)庫一起工作的應用程序交互的系統(tǒng)。另外,測試需要隨著代碼的改變而更新。

因此,在決定采用TDD方法之前,應考慮上述因素,并應根據(jù)項目的性質(zhì)采取措施。

四.測量代碼覆蓋率

代碼覆蓋率衡量(以百分比表示)了在運行單元測試時執(zhí)行的代碼量。通常,高覆蓋率的代碼包含未檢測到的錯誤的幾率要低,因為其更多的源代碼在測試過程中被執(zhí)行。測量代碼覆蓋率的一些最佳做法包括:

  1. 使用代碼覆蓋工具,如Clover,Corbetura,JaCoCo或Sonar。使用工具可以提高測試質(zhì)量,因為這些工具可以指出未經(jīng)測試的代碼區(qū)域,讓你能夠開發(fā)開發(fā)額外的測試來覆蓋這些領域。

  2. 每當寫入新功能時,立即寫新的測試覆蓋。

  3. 確保有測試用例覆蓋代碼的所有分支,即if / else語句。

高代碼覆蓋不能保證測試是完美的,所以要小心!

下面的 concat 方法接受布爾值作為輸入,并且僅當布爾值為true時附加傳遞兩個字符串:

public String concat(boolean append, String a,String b) {
  String result = null;
  If (append) {
   result = a + b;
       }
  return result.toLowerCase();
}
以下是上述方法的測試用例:
@Test
public void testStringUtil() {
  String result = stringUtil.concat(true, "Hello ", "World");
  System.out.println("Result is "+result);
}

在這種情況下,執(zhí)行測試的值為true。當測試執(zhí)行時,它將通過。當代碼覆蓋率工具運行時,它將顯示100%的代碼覆蓋率,因為 concat 方法中的所有代碼都被執(zhí)行。但是,如果測試執(zhí)行的值為false,則將拋出 NullPointerException 。所以100%的代碼覆蓋率并不真正表明測試覆蓋了所有場景,也不能說明測試良好。

五.盡可能將測試數(shù)據(jù)外部化

在JUnit4之前,測試用例要運行的數(shù)據(jù)必須硬編碼到測試用例中。這導致了限制,為了使用不同的數(shù)據(jù)運行測試,測試用例代碼必須修改。但是,JUnit4以及TestNG支持外部化測試數(shù)據(jù),以便可以針對不同的數(shù)據(jù)集運行測試用例,而無需更改源代碼。

下面的 MathChecker 類有方法可以檢查一個數(shù)字是否是奇數(shù):

public class MathChecker {
  public Boolean isOdd(int n) {
   if (n%2 != 0) {
    return true;
   } else {
    return false;
   }
  }
 }

以下是MathChecker類的TestNG測試用例:

public class MathCheckerTest {
  private MathChecker checker;
  @BeforeMethod
  public void beforeMethod() {
   checker = new MathChecker();
  }
  @Test
  @Parameters("num")
  public void isOdd(int num) {
   System.out.println("Running test for "+num);
   Boolean result = checker.isOdd(num);
   Assert.assertEquals(result, new Boolean(true));
  }
 }
TestNG

以下是testng.xml(用于TestNG的配置文件),它具有要為其執(zhí)行測試的數(shù)據(jù):

<?xml version="1.0" encoding="UTF-8"?>
 <suite name="ParameterExampleSuite" parallel="false">
 <test name="MathCheckerTest">
 <classes>
  <parameter name="num" value="3"></parameter>
  <class name="com.stormpath.demo.MathCheckerTest"/>
 </classes>
  </test>
  <test name="MathCheckerTest1">
 <classes>
  <parameter name="num" value="7"></parameter>
  <class name="com.stormpath.demo.MathCheckerTest"/>
 </classes>
  </test>
 </suite>

可以看出,在這種情況下,測試將執(zhí)行兩次,值3和7各一次。除了通過XML配置文件指定測試數(shù)據(jù)之外,還可以通過DataProvider注釋在類中提供測試數(shù)據(jù)。

六.JUnit

與TestNG類似,測試數(shù)據(jù)也可以外部化用于JUnit。以下是與上述相同MathChecker類的JUnit測試用例:

@RunWith(Parameterized.class)
 public class MathCheckerTest {
  private int inputNumber;
  private Boolean expected;
  private MathChecker mathChecker;
  @Before
  public void setup(){
   mathChecker = new MathChecker();
  }
  // Inject via constructor
  public MathCheckerTest(int inputNumber, Boolean expected) {
   this.inputNumber = inputNumber;
   this.expected = expected;
  }
  @Parameterized.Parameters
  public static Collection<Object[]> getTestData() {
   return Arrays.asList(new Object[][]{
     {1, true},
     {2, false},
     {3, true},
     {4, false},
     {5, true}
   });
  }
  @Test
  public void testisOdd() {
   System.out.println("Running test for:"+inputNumber);
   assertEquals(mathChecker.isOdd(inputNumber), expected);
  }
 }

可以看出,要對其執(zhí)行測試的測試數(shù)據(jù)由getTestData()方法指定。此方法可以輕松地修改為從外部文件讀取數(shù)據(jù),而不是硬編碼數(shù)據(jù)。

七.使用斷言而不是Print語句

許多新手開發(fā)人員習慣于在每行代碼之后編寫System.out.println語句來驗證代碼是否正確執(zhí)行。這種做法常常擴展到單元測試,從而導致測試代碼變得雜亂。除了混亂,這需要開發(fā)人員手動干預去驗證控制臺上打印的輸出,以檢查測試是否成功運行。更好的方法是使用自動指示測試結果的斷言。

下面的 StringUti 類是一個簡單類,有一個連接兩個輸入字符串并返回結果的方法:

public class StringUtil {
  public String concat(String a,String b) {
   return a + b;
  }
 }

以下是上述方法的兩個單元測試:

@Test
 public void testStringUtil_Bad() {
   String result = stringUtil.concat("Hello ", "World");
   System.out.println("Result is "+result);
 }
 @Test
 public void testStringUtil_Good() {
   String result = stringUtil.concat("Hello ", "World");
   assertEquals("Hello World", result);
 }

testStringUtil\_Bad將始終傳遞,因為它沒有斷言。開發(fā)人員需要手動地在控制臺驗證測試的輸出。如果方法返回錯誤的結果并且不需要開發(fā)人員干預,則testStringUtil\_Good將失敗。

八.構建具有確定性結果的測試

一些方法不具有確定性結果,即該方法的輸出不是預先知道的,并且每一次都可以改變。例如,考慮以下代碼,它有一個復雜的函數(shù)和一個計算執(zhí)行復雜函數(shù)所需時間(以毫秒為單位)的方法:

public class DemoLogic {
 private void veryComplexFunction(){
  //This is a complex function that has a lot of database access and is time consuming
  //To demo this method, I am going to add a Thread.sleep for a random number of milliseconds
  try {
   int time = (int) (Math.random()*100);
   Thread.sleep(time);
  } catch (InterruptedException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }
 public long calculateTime(){
  long time = 0;
  long before = System.currentTimeMillis();
  veryComplexFunction();
  long after = System.currentTimeMillis();
  time = after - before;
  return time;
 }
 }

在這種情況下,每次執(zhí)行 calculateTime 方法時,它將返回一個不同的值。為該方法編寫測試用例不會有任何用處,因為該方法的輸出是可變的。因此,測試方法將不能驗證任何特定執(zhí)行的輸出。

九.除了正面情景外,還要測試負面情景和邊緣情況

通常,開發(fā)人員會花費大量的時間和精力編寫測試用例,以確保應用程序按預期工作。然而,測試負面測試用例也很重要。負面測試用例指的是測試系統(tǒng)是否可以處理無效數(shù)據(jù)的測試用例。例如,考慮一個簡單的函數(shù),它能讀取長度為8的字母數(shù)字值,由用戶鍵入。除了字母數(shù)字值,應測試以下負面測試用例:

  1. 用戶指定非字母數(shù)字值,如特殊字符。

  2. 用戶指定空值。

  3. 用戶指定大于或小于8個字符的值。

類似地,邊界測試用例測試系統(tǒng)是否適用于極端值。例如,如果用戶希望輸入從1到100的數(shù)字值,則1和100是邊界值,對這些值進行測試系統(tǒng)是非常重要的。

以上就是本文的全部內(nèi)容,希望本文的內(nèi)容對大家的學習或者工作能帶來一定的幫助,同時也希望多多支持腳本之家!

相關文章

  • Java Scala偏函數(shù)與偏應用函數(shù)超詳細講解

    Java Scala偏函數(shù)與偏應用函數(shù)超詳細講解

    Scala是一種多范式的編程語言,支持面向?qū)ο蠛秃瘮?shù)式編程。Scala也支持異常處理,即在程序運行過程中發(fā)生意外或錯誤時,采取相應的措施
    2023-04-04
  • Spring代理對象導致的獲取不到原生對象注解的解決

    Spring代理對象導致的獲取不到原生對象注解的解決

    本文主要介紹了Spring代理對象導致的獲取不到原生對象注解的解決,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-04-04
  • java秒殺之redis限流操作詳解

    java秒殺之redis限流操作詳解

    這篇文章主要為大家詳細介紹了java秒殺之redis限流操作,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • PowerJob的GridFsManager工作流程源碼解讀

    PowerJob的GridFsManager工作流程源碼解讀

    這篇文章主要為大家介紹了PowerJob的GridFsManager工作流程源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2024-01-01
  • JAVA定義變量與輸出詳解

    JAVA定義變量與輸出詳解

    這篇文章主要介紹了JAVA定義變量與輸出詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-07-07
  • Java中指定時區(qū)的3種方法

    Java中指定時區(qū)的3種方法

    這篇文章主要介紹了Java中指定時區(qū)的3種方法,本文是一個JAVA項目和.NET項目通訊時遇到的問題,本文給出JAVA中的3種解決方法,需要的朋友可以參考下
    2015-02-02
  • java Runtime如何執(zhí)行多條命令

    java Runtime如何執(zhí)行多條命令

    這篇文章主要介紹了java Runtime如何執(zhí)行多條命令,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • IDEA?報Plugin'maven-resources-plugin:'not?found?的解決方案

    IDEA?報Plugin'maven-resources-plugin:'not?found?

    如果在使用?IDEA?時遇到?"Plugin?'maven-resources-plugin:'?not?found"?錯誤,可能是由于?Maven?倉庫中未找到所需的?Maven?插件,近小編給大家分享幾種解決方法,感興趣的朋友跟隨小編一起看看吧
    2023-07-07
  • 淺談java中BigDecimal的equals與compareTo的區(qū)別

    淺談java中BigDecimal的equals與compareTo的區(qū)別

    下面小編就為大家?guī)硪黄獪\談java中BigDecimal的equals與compareTo的區(qū)別。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-11-11
  • MyBatis通用的10種寫法總結大全

    MyBatis通用的10種寫法總結大全

    這篇文章主要給大家介紹了關于MyBatis通用的10種寫法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2018-11-11

最新評論