常用鏈接

          統計

          最新評論

          單元測試(Unit Test)(轉)

          B.1 單元測試(Unit Test)

          一個單元(Unit)是指一個可獨立進行的工作,獨立進行指的是這個工作不受前一次或接下來的工作的結果影響。簡單地說,就是不與程序運行時的上下文(Context)發生關系。

          如果是在Java程序中,具體來說一個單元可以是指一個方法(Method)。這個方法不依賴于前一次運行的結果,也不牽涉到后一次的運行結果。

          舉例來說,下面這個程序的gcd()方法可視為一個單元:

          Ü MathTool.java

          package onlyfun.caterpillar;

          public class MathTool {

              public static int gcd(int num1, int num2) {

                  int r = 0;

                  while(num2 != 0) {

                      r = num1 % num2;

                      num1 = num2;

                      num2 = r;

                  }

                  return num1;

              }

          }

          下面的gcd()方法不可視為一個單元,要完成gcd的計算,必須調用setNum1()setNum2()gcd() 3個方法。

          Ü MathFoo.java

          package onlyfun.caterpillar;

          public class MathFoo {

              private static int num1;

              private static int num2;

              public static void setNum1(int n) {

                  num1 = n;

              }

              public static void setNum2(int n) {

                  num2 = n;

              }

              public static int gcd() {

                  int r = 0;

                  while(num2 != 0) {

                      r = num1 % num2;

                      num1 = num2;

                      num2 = r;

                  }

                  return num1;

              }

          }

          然而要完全使用一個方法來完成一個單元操作在實現上是有困難的,所以單元也可廣義解釋為數個方法的集合。這數個方法組合為一個單元操作,目的是完成一個任務。

          不過設計時仍優先考慮將一個公開的方法設計為單元,輔助的方法則使用設定為私用,盡量不用數個公開的方法來完成一件工作,以保持接口簡潔與單元邊界清晰。將工作以一個單元進行設計,這使得單元可以重用,并且也使得單元可以進行測試,進而增加類的可重用性。

          單元測試指的是對每一個工作單元進行測試,了解其運行結果是否符合我們的要求。例如當編寫完MathTool類之后,也許會這么寫一個小小的測試程序:

          Ü MathToolTest.java

          package test.onlyfun.caterpillar;

          import onlyfun.caterpillar.MathTool;

          public class MathToolTest {

              public static void main(String[] args) {

                  if(MathTool.gcd(10, 5) == 5) {

                      System.out.println("GCD Test OK!");

                  }

                  else {

                      System.out.println("GCD Test Fail!");

                  }

              }

          }

          在文字模式下使用文字信息顯示測試結果,這個動作是開發人員經常作的事情,然而您必須一行一行看著測試程序的輸出結果,以了解測試是否成功。另一方面,測試程序本身也是一個程序,在更復雜的測試中,也許會遇到測試程序本身出錯,而導致無法驗證結果的情況。

          JUnit是一個測試框架,通過它所提供的工具,可以減少編寫錯誤的測試程序的機會。另一方面,可以有更好的方法來檢驗測試結果,而不是看著一長串輸出的文字來檢驗測試是否成功。JUnit測試框架讓測試的進行更有效率且更具可靠性。

          B.2 JUnit設置

          JUnit最初是由Erich GammaKent Beck編寫,為單元測試的支持框架,用來編寫與執行重復性的測試。它包括以下特性:

          Ü   對預期結果作判斷

          Ü   提供測試裝備的生成與銷毀

          Ü   易于組織與執行測試

          Ü   圖形與文字接口的測試器

          要設定JUnit,可先到 JUnit官方網站(http://junit.org/)下載JUnitzip文件,下載后解開壓縮文件,其中會含有junit.jar文件,將這個文件復制到所要的數據夾中,然后設定Classpath指向junit.jar。例如:

          set classpath=%classpath%;YOUR_JUNIT_DIR\junit.jar

          如果是Windows 2000/XP,可以在環境變量中設定Classpath變量(可參考附錄A中的Classpath設置介紹)

          B.3 第一個JUnit測試

          要對程序進行測試,首先要設計測試案例(Test Case)。一個測試案例是對程序給予假定條件,然后運行程序并看看在給定的條件下,程序的運行結果是否符合要求。

          JUnit下,可以繼承TestCase來編寫測試案例,并定義測試方法,每一個測試方法是以testXXX()來命名。一個例子如下所示:

           

          Ü MathToolUnitTest.java

          package test.onlyfun.caterpillar;

           

          import onlyfun.caterpillar.MathTool;

          import junit.framework.TestCase;

           

          public class MathToolUnitTest extends TestCase {

              public void testGcd() {

                  assertEquals(5, MathTool.gcd(10, 5));

              }

             

              public static void main(String[] args) {

                  junit.textui.TestRunner.run(MathToolUnitTest.class);

              }

          }

          assertEquals()方法用來斷定您的預期值與單元方法實際的返回結果是否相同,如果預期值與返回的結果不同則丟出異常,TestRunner會捕捉異常,并提取其中的相關信息以報告測試結果。這里使用的是文字模式的TestRunner

          接下來根據測試案例編寫實際的程序,首先試著讓測試案例能通過編譯:

          package onlyfun.caterpillar;
           
          public class MathTool {
              public static int gcd(int num1, int num2) { 
                  return 0;
              }
          }

          編譯完MathTool.java并用javac來編譯它。在編譯完成之后,接著運行測試案例,會得到以下的結果:

          .F
          Time: 0
          There was 1 failure:
          1) testGcd(test.onlyfun.caterpillar.MathToolUnitTest)junit.framework.AssertionFa
          iledError: expected:<5> but was:<0>
          ...
          FAILURES!!!
          Tests run: 1,  Failures: 1,  Errors: 0

          由于MathTool中并沒有編寫什么實際的邏輯,所以測試失敗。在測試驅動中,測試案例所報告的結果通常是以測試失敗作為開始,您的挑戰就是要一步步消除這些失敗的信息。接下來根據測試案例,完成所設計的程序:

          Ü MathTool.java

          package onlyfun.caterpillar;

           

          public class MathTool {

              public static int gcd(int num1, int num2) {

                  int r = 0;

                  while(num2 != 0) {

                      r = num1 % num2;

                      num1 = num2;

                      num2 = r;

                  }

                  return num1;

              }

          }

          再次運行測試案例,會得到以下的結果,通過最后的OK信息,知道測試已經成功:

          .Time: 0
           
          OK (1 test)

          不一定要在main()中指定TestRunner,而可以直接啟動一個TestRunner,并指定測試案例類(繼承TestCase的類)。例如啟動一個Swing窗口的測試結果畫面:

          java junit.swingui.TestRunner test.onlyfun.caterpillar.MathToolUnitTest

          執行的結果畫面如圖B-1所示。

          Swing窗口的測試結果顯示中,如果中間的橫棒是顯示綠色,表示所有的測試都已經成功,如果中間的橫棒顯示紅色,表示測試失敗。JUnit的名言Keep the bar green to keep the code clean,意思是保持綠色橫棒以保證測試成功。

          也可以指定文字模式的測試結果。例如:

          java junit.textui.TestRunner test.onlyfun.caterpillar.MathToolUnitTest

          B-1  JUnitSwing窗口測試結果

          B.4 自動構建與測試

          Ant可以進行自動化構建,而JUnit可以進行自動化測試,Ant可以與JUnit結合,使得自動化的構建與測試變得可行。

          如果要讓Ant能支持JUnit,建議直接將JUnitjunit.jar放置在Antlib目錄,并記得改變Classpath中原先有關junit.jar的設定。例如將Classpath重新指向%ANT_HOME%\lib\junit.jar(假設已經如附錄A中設置了ant_home的環境變量)。雖然也有其他的方式可以設定,但這是最快也是最簡單的方法。

          Ant使用<junit>標簽來設定JUnit測試,下面是一個簡單的例子:

           

          <?xml version="1.0"?>

          <project name="autoBuildTest" default="test">

              <target name="setProperties">

                  <property name="src.dir" value="src"/>

                  <property name="classes.dir" value="classes"/>

              </target>

           

              <target name="prepareDir" depends="setProperties">

                  <delete dir="${classes.dir}"/>

                  <mkdir dir="${classes.dir}"/>

              </target>

           

              <target name="compile" depends="prepareDir">

                  <javac srcdir="${src.dir}" destdir="${classes.dir}"/>

              </target>

           

              <target name="test" depends="compile">

                  <junit printsummary="yes">

                      <test

                         name="test.onlyfun.caterpillar.MathToolUnitTest"/>

                      <classpath>

                          <pathelement location="${classes.dir}"/>

                      </classpath>

                  </junit>

              </target>

          </project>

          printsummary屬性會將測試的結果簡單地顯示出來,<test>name屬性是設定所要進行測試的測試案例類。Ant構建與調用JUnit進行測試的信息如下:

          C:\workspace\B>ant
          Buildfile: build.xml
           
          setProperties:
           
          prepareDir:
              [mkdir] Created dir: C:\workspace\B\classes
           
          compile:
              [javac] Compiling 4 source files to C:\workspace\B\classes
           
          test:
              [junit] Running test.onlyfun.caterpillar.MathToolUnitTest
              [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0 sec
           
          BUILD SUCCESSFUL
          Total time: 1 second

          B.5 自動生成測試報告

          接上一個主題,可以將JUnit的測試過程在Ant構建過程中顯示出來,只要加入< formatter>標簽設定即可:

          <?xml version="1.0"?>
          <project name="autoBuildTest" default="test">
              ...
              <target name="test" depends="compile"> 
                  <junit printsummary="yes"> 
                      <formatter type="plain" usefile="false"/>
                      <test 
                         name="test.onlyfun.caterpillar.MathToolUnitTest"/> 
                      <classpath> 
                          <pathelement location="${classes.dir}"/> 
                      </classpath> 
                  </junit> 
              </target>
          </project>

          Ant構建與調用JUnit進行測試的信息如下:

          C:\workspace\B>ant
          Buildfile: build.xml
           
          setProperties:
           
          prepareDir:
             [delete] Deleting directory C:\workspace\B\classes
              [mkdir] Created dir: C:\workspace\B\classes
           
          compile:
              [javac] Compiling 4 source files to C:\workspace\B\classes
           
          test:
              [junit] Running test.onlyfun.caterpillar.MathToolUnitTest
              [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.016 sec
              [junit] Testsuite: test.onlyfun.caterpillar.MathToolUnitTest
              [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.016 sec
           
              [junit] Testcase: testGcd took 0.016 sec
           
          BUILD SUCCESSFUL
          Total time: 2 seconds

          usefile屬性設定為true時,會自動將產生的結果保存在文件中,默認是TEST-*.txt。其中*是測試案例類名稱。就上例而言,所產生的報告文件內容如下:

          Testsuite: test.onlyfun.caterpillar.MathToolUnitTest
          Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0 sec
           
          Testcase: testGcd took 0 sec

          <formatter>標簽還可以設定將測試的結果,以XML文件保存下來。一個編寫的例子如下,它將測試的結果保存至report目錄中, 文件名稱為TEST-*.xml*是測試案例類名稱:

          <?xml version="1.0"?>
              ...
              <target name="test" depends="compile"> 
                  <junit printsummary="yes"> 
                      <formatter type="xml"/>
                      <test 
                         name="test.onlyfun.caterpillar.MathToolUnitTest"/> 
                      <classpath> 
                          <pathelement location="${classes.dir}"/> 
                      </classpath> 
                  </junit> 
              </target>
          </project>

          也可以將測試結果所產生的XML文件轉換為HTML文件,使用Ant可以直接完成這個工作。<junitreport>標簽使用 XSLTXML文件轉換為HTML文件。下面的例子將前面的說明作個總結,以完整呈現編寫的實例:

          Ü build.xml

          <?xml version="1.0"?>

          <project name="autoBuildTest" default="report">

              <target name="setProperties">

                  <property name="src.dir" value="src"/>

                  <property name="classes.dir" value="classes"/>

                  <property name="report.dir" value="report"/>       

              </target>

           

              <target name="prepareDir" depends="setProperties">

                  <delete dir="${report.dir}"/>

                  <delete dir="${classes.dir}"/>

                  <mkdir dir="${report.dir}"/>

                  <mkdir dir="${classes.dir}"/>

              </target>

           

              <target name="compile" depends="prepareDir">

                  <javac srcdir="${src.dir}" destdir="${classes.dir}"/>

              </target> 

           

              <target name="test" depends="compile">

                  <junit printsummary="yes">

                      <formatter type="xml"/>

                      <test

                         name="test.onlyfun.caterpillar.MathToolUnitTest"/>

                      <classpath>

                          <pathelement location="${classes.dir}"/>

                      </classpath>

                  </junit>

              </target>

             

              <target name="report" depends="test">

                  <junitreport todir="${report.dir}">

                      <fileset dir="${report.dir}">

                          <include name="TEST-*.xml"/>

                      </fileset>

                      <report

                          format="frames" todir="${report.dir}/html"/>

                  </junitreport>

              </target>   

          </project>

          <include>設定搜尋TEST-*.xml文件,將之轉換為HTML文件,而最后的結果被設定保存至report/html/目錄下,在format屬性中設定了HTML文件具有邊框(Frame),如果不設定這個屬性,則HTML報告文件就不具有邊框。在運行Ant之后所產生的 HTML測試結果報告文件如圖B-2所示。

          B-2  Ant結合JUnit所自動產生的測試報告

          附錄B只是對JUnit的一些簡介,如果需要更多有關JUnit的資料,可以參考以下的網址:

          http://caterpillar.onlyfun.net/Gossip/JUnit/JUnitGossip.htm

          posted on 2008-01-08 10:03 九寶 閱讀(527) 評論(0)  編輯  收藏 所屬分類: Java

          主站蜘蛛池模板: 响水县| 本溪| 顺平县| 定南县| 莱阳市| 类乌齐县| 天等县| 阿图什市| 璧山县| 大石桥市| 宁海县| 蓝山县| 新蔡县| 新兴县| 璧山县| 绥芬河市| 来安县| 游戏| 常德市| 乐至县| 临安市| 辽宁省| 牟定县| 尤溪县| 山丹县| 平顶山市| 同心县| 台安县| 西充县| 阿克苏市| 淅川县| 锦屏县| 鄯善县| 手机| 南通市| 阿拉善左旗| 襄垣县| 博客| 林口县| 济宁市| 丽水市|