皇家方舟

          Junit4功能 先睹為快. (譯文) (轉)

          An early look at JUnit 4

          Upcoming release promises evolution in testing

          難度級別: 中

          Elliotte Harold (elharo@metalab.unc.edu), Adjunct Professor, Polytechnic University

          2005-9-15 (譯)

          原文:http://www-128.ibm.com/developerworks/java/library/j-junit4.html

          JUnit 是JAVA語言事實上的標準測試庫。JUnit 4是三年以來最具里程碑意義的一次發布。它的新特性主要是針對JAVA5中的標記(annotation)來簡化測試,而不是利用子類、反射或命名機制。本文將講述如何使用JUnit 4,當前前提是你最好具有JUnit的使用經驗.

          JUnit, 由Kent Beck?和 Erich Gamma開發,幾乎是JAVA開發最重要的第三方工具。正如Martin Fowler 所說,“在軟件開發領域,從來就沒有如此少的代碼起到了如此重要的作用“。由于JUnit,JAVA代碼變得更健壯,更可靠,BUG也比以前更少。由于JUnit (由Smalltalk's的SUnit得來) 的出現,隨后產生了許多xUnit的測試工具,如nUnit (.NET), pyUnit (Python), CppUnit (C++), dUnit (Delphi) 和其它不同平臺及語言的測試相關的工具。

          雖然JUnit也只是一個工具,但其產生的思想和技術卻較其架構更意義重大。單元測試,測試先行的編程方式,測試驅動的開發方式,并非必須由JUNIT實現,也不一定要用SWing實現GUI界面。JUNIT最近的一次更新是在三年前,但它比其它大多數有BUG的框架都要健壯,更重要的是,JAVA一直在改進。現在JAVA支持泛型,枚舉,可變長度參數,以及標記語言(開創了開發可重用框架的新局面)。

          JUnit's的停滯不前使得那些想要變革的開發人員換其它測試工具.挑戰者有Bill Venners的Artima SuiteRunner和Cedric Beust的TestNG.這些工具庫雖然有值得推薦的功能,但沒有任何一款的地位能與JUNIT相比,沒有任何一款工具被其它業界產品如Ant, Maven, Eclipse廣泛支持.因此Beck 和Gamma雙開始利用JAVA5的新特性來開發新版的JUNIT,目的是利用JAVA5中的標記特性使得單元測試開發更容易。Beck說:“JUNIT4的主要目的是通過簡化JUNIT的使用鼓勵更多的開發人員寫更多的測試”。雖然會與以前的版本兼容,但JUNIT4與從JUNIT1.0就開始的版本相比會有一個非常大的變化.

          注意: 修改基本框架是一把雙刃劍,雖然JUNIT4的目的是清晰的,但細節仍有許多不同,因此本文只是一個簡單的介紹,并不是最終文檔.

          測試方法

          以前所有版本的JUNIT都使用命名機制和反射來定位測試,下面的代碼測試1+1= 2:

          																				import junit.framework.TestCase;
          
          public class AdditionTest extends TestCase {
          
            private int x = 1;
            private int y = 1;
            
            public void testAddition() {
              int z = x + y;
              assertEquals(2, z);
            }
          
          }
          																		

          而在JUNIT 4中,測試方法由@Test 標記說明,如下:

          																				import org.junit.Test;
          import junit.framework.TestCase;
          
          public class AdditionTest extends TestCase {
          
            private int x = 1;
            private int y = 1;
            
            @Test public void testAddition() {
              int z = x + y;
              assertEquals(2, z);
            }
          
          }
          																		

          使用標記的好處是你不用將所有測試方法命名為 testFoo(), testBar()等等以"test"開頭的方法,下面的方法也同樣可以工作:

          																				import org.junit.Test;
          import junit.framework.TestCase;
          
          public class AdditionTest extends TestCase {
          
            private int x = 1;
            private int y = 1;
            
            @Test public void additionTest() {
              int z = x + y;
              assertEquals(2, z);
            }
          
          }
          																		

          下面的代碼也同樣正確:

          																				import org.junit.Test;
          import junit.framework.TestCase;
          
          public class AdditionTest extends TestCase {
          
            private int x = 1;
            private int y = 1;
            
            @Test public void addition() {
              int z = x + y;
              assertEquals(2, z);
            }
          
          }
          																		

          這種命名機制最大的優點是更適合你的待測試類或方法名稱,例如,你可以使用ListTEst.contains()測試 List.contains();使用ListTest.addAll()測試 List.add()等等.

          TestCase還可以繼續使用,但你沒有必須再擴展為子類,只要你聲明了@Test,你可以將測試方法放在任何類中,當然如要訪問assert等方法,你必須要引用junit.Assert類,如下:

          																				import org.junit.Assert;
          
          public class AdditionTest {
          
            private int x = 1;
            private int y = 1;
            
            @Test public void addition() {
              int z = x + y;
              Assert.assertEquals(2, z);
            }
          
          }
          																		

          你也可以使用JDK5中的新特性(static import)使得跟以前版本一樣簡單:

          																				import static org.junit.Assert.assertEquals;
          
          public class AdditionTest {
          
            private int x = 1;
            private int y = 1;
            
            @Test public void addition() {
              int z = x + y;
              assertEquals(2, z);
            }
          
          }
          																		

          這種方法測試受保護的方法非常容易,因為你可以在測試類中繼承有受保護方法的類.



          Back to top


          SetUp 和TearDown

          JUnit 3 中test runners 會在每個測試之前自動調用 setUp()方法。此方法主要用于初始化變量,打開日志,重置環境變量等。下面是XOM's XSLTransformTest中的setUp()方法:

          																				protected void setUp() {
                  
              System.setErr(new PrintStream(new ByteArrayOutputStream()));
                  
              inputDir = new File("data");
              inputDir = new File(inputDir, "xslt");
              inputDir = new File(inputDir, "input");
                  
          }
          																		

          在JUnit 4中,你仍然可以在每個測試前初始化變量和配置環境,,然而,這些操作可以不用在Setup()中完成,你可以在初始化方法前面添加@Beforer 來表示,如下:

          																				@Before protected void initialize() {
                  
              System.setErr(new PrintStream(new ByteArrayOutputStream()));
                  
              inputDir = new File("data");
              inputDir = new File(inputDir, "xslt");
              inputDir = new File(inputDir, "input");
                  
          }
          																		

          你也可以有多個方法標記有@Before,所有方法都會在每個測試之前執行:

          																				@Before protected void findTestDataDirectory() {
              inputDir = new File("data");
              inputDir = new File(inputDir, "xslt");
              inputDir = new File(inputDir, "input");
          }
              
           @Before protected void redirectStderr() {
              System.setErr(new PrintStream(new ByteArrayOutputStream()));
          }
          																		

          清除環境與JUNIT3 差不多,在JUNIT3中使用 tearDown()方法,下面的代碼是結束測試時回收內存:

          																				protected void tearDown() {
            doc = null;
            System.gc();   
          } 
          																		

          在JUnit 4中,你還可以使用@After標記來說明:

          																				@After protected void disposeDocument() {
            doc = null;
            System.gc();   
          } 
          																		

          @Before一樣,你也可以有多個標記有@After的清除方法,每個都會在執行完每個測試后執行。

          最后,你不需要在父類中明確調用這些初始化或清除方法.test runner會自動調用這些標記的方法.子類中的@Before方法在父類的@Before方法之后執行(這與構造函數的執行順序一樣),而@After方法剛好相反,子類中的@After方法先執行.然而,多個@Before和@After方法的執行順序就是未知的.

          測試集范圍的初始化

          JUnit 4中引入了一項JUNIT3沒有的新特性,類級別的setUp()和tearDown(),即在一個類的所有測試前執行初始化,并在所有測試完成后執行清除。

          例如,一個測試類中的每個測試都要用到一個數據庫連接或網絡連接,或其它很耗資源初始化或釋放的資源,用不著在每個測試方法前后進行操作,而只需要在測試類開始前后執行即可。下面的示例是使用第三方的庫進行錯誤,在執行所有測試前將錯誤先重定向到非標準輸出,然后在所有測試結束后再輸出到需要的地方,這樣就不會影響到測試過程中產生的其它信息。

          																				// This class tests a lot of error conditions, which
          // Xalan annoyingly logs to System.err. This hides System.err 
          // before each test and restores it after each test.
          private PrintStream systemErr;
              
          @BeforeClass protected void redirectStderr() {
              systemErr = System.err; // Hold on to the original value
              System.setErr(new PrintStream(new ByteArrayOutputStream()));
          }
              
          @AfterClass protected void tearDown() {
              // restore the original value
              System.setErr(systemErr);
          }
          																		

          上面的操作沒有必須在每個測試前后執行。然而要注意的是,這種方法可能影響測試間的結果,如果一個測試改變了初始化的對象,而這個對象可能是其它測試的輸入,那么測試的結果可能不正確,這種方法將依賴測試的順序并可能引入BUG。當優化測試性能,并且當你改進了配置和基準測試后而仍然很慢時,如數據庫連接或網絡問題,你才需要考慮使用這種方法。只有這樣,你才能每天執行多次測試。



          Back to top


          異常測試

          異常測試是JUNIT4中的最大的改進,以前異常測試是通過try catch實現,當拋出異常時,在try的最后添加一條fail()語句實現.如下:

          																				public void testDivisionByZero() {
              
              try {
                  int n = 2 / 0;
                  fail("Divided by zero!");
              }
              catch (ArithmeticException success) {
                  assertNotNull(success.getMessage());
              }
              
          }
          																		

          這種方法不僅難看,而且造成無論成功或失敗,代碼覆蓋工具都不能執行某些代碼.而在JUnit 4中,你可以在要拋出異常的代碼中添加標記來聲明一個異常是期望的:

          																				@Test(expected=ArithmeticException.class) public void divideByZero() {
              int n = 2 / 0;
          }
          																		

          如果沒有異常拋出,上面的測試則會失敗,如果你想知道異常的詳細信息或其它情況,你還是要使用try catch才行


          Back to top


          需要忽略的測試

          也許你有些測試需要很長時間才能執行完成,并非是這個測試應該跑得快,而是它做的很復雜和很慢的工作造成的.如訪問遠程網絡錯誤,需要很久才能有反饋.如果你不想讓這種測試破壞你整個測試過程,你可能想跳過這個測試.當然也有可能某個測試超出控制范圍而失敗.如W3C XInclude測試集中自動識別一些JAVA不支持的Unicode代碼.為了防止這些測試總是通不過,可以使用標記 @Ignore跳過這些測,如下:

          																				// Java doesn't yet support the UTF-32BE and UTF32LE encodings
              @Ignore public void testUTF32BE() 
                throws ParsingException, IOException, XIncludeException {
                
                  File input = new File(
                    "data/xinclude/input/UTF32BE.xml"
                  );
                  Document doc = builder.build(input);
                  Document result = XIncluder.resolve(doc);
                  Document expectedResult = builder.build(
                    new File(outputDir, "UTF32BE.xml")
                  );
                  assertEquals(expectedResult, result);
                          
              }
          																		

          test runner不會執行這些測試,但會說明這些測試被跳過了。在命令行測試界面中,字母“I”會表示測試跳過,或“E”表示測試失敗,而不是用點”."表示成功.

          																				$ java -classpath .:junit.jar org.junit.runner.JUnitCore nu.xom.tests.XIncludeTest
          JUnit version 4.0rc1
          .....I..
          Time: 1.149
          
          OK (7 tests)
          																		

          要注意的是,假設這些測試由于某種理由放在最開始,如果你以后一直忽略這些測試,那些需要被測試的代碼可能有問題而不會被檢測到。因此忽略測試只是一個臨時解決方法,并不是一個解決任何問題的真正辦法。



          Back to top


          時間測試

          性能測試是單元測試中最頭疼的問題,JUnit 4也未完全解決此問題, 你可以在JUNIT4的測試方法中添加一個時間參數。如果測試時間超過參數,則測試失敗。如下,如果測試時間超過0.5秒,則此測試失敗:

          																				
          @Test(timeout=500) public void retrieveAllElementsInDocument() {
              doc.query("http://*");
          } 
          																		

          除基準性能測試外,時間測試在網絡測試方面也很有用.如果一個遠端的主機或數據當掉或太慢,你可以跳過此測試而不用阻塞在這里,好的測試集可以在作了一些改動后很快的一遍一遍的執行,可能一天數十次.設置一個超時讓測試更快的執行,下面的示例中如果分析http://www.ibiblio.org/xml 的時間超過2秒,則測試失敗.

          																				
          @Test(timeout=2000) 
            public void remoteBaseRelativeResolutionWithDirectory()
             throws IOException, ParsingException {
                builder.build("http://www.ibiblio.org/xml");
            } 
          																		



          Back to top


          新的斷言

          JUnit 4 增加了兩上斷文方法用于比較數組:

          																				
          public static void assertEquals(Object[] expected, Object[] actual)
          public static void assertEquals(String message, Object[] expected, 
          Object[] actual)
          
          																		

          這兩個方法采用最直接方法比較,如果數組長度相同,且每個對應的元素相同,則比較成功,否則不成功.參數為空的情況也作了考慮.


          Back to top


          需要補充的地方

          JUnit 4是一個非常基本的框架,還不是以前版本的升級。JUNIT3的開發人員會發現有些功能沒有。

          • 最大的特點就是沒有GUI測試界面,當測試正確時是綠色條,而出錯時紅色的,你也可以在Eclipse中集成JUNIT使用,但JUNIT4既沒有AWT也沒有SWING的GUI測試界面;
          • 另一個讓人吃驚的是失敗(期望錯誤)和錯誤(未預計的異常錯誤)沒有明顯區別,在JUNIT3中開發人員可以區分這兩種情況,而在JUNIT4中不行;
          • 最后一個特點是JUNIT中沒有用于建立一堆測試類的suite()方法,取而代之的是,采用變長參數傳遞未知數量的測試給test runner。

          沒有GUI測試界面的確不方便,但其它改變簡化了JUNIT的使用,從當前JUNIT的操作手冊和FAQ的數量就知道,而JUNIT4的文檔將不會需要這么多。



          Back to top


          編譯和運行JUnit 4

          現在JUnit 4還沒有發布編譯版本,如果想體驗版本的樂趣,則需要從CVS中獲取源代碼。分支標簽是"Version4" (see Resources ).要注意的是大部分文檔是根據JUNIT3編寫的,還未同步更新。需要Java 5才能編譯JUnit 4,因為大量使用了標記,泛型其其它JDK5中的新特性。

          執行測試的命令行方式與JUNIT3有點區別,你現在要使用 org.junit.runner.JUnitCore 類進行測試,如下:

          																				
          $ java -classpath .:junit.jar org.junit.runner.JUnitCore 
            TestA TestB TestC...
          JUnit version 4.0rc1
          
          Time: 0.003
          
          OK (0 tests)
          																		

          兼容性

          Beck 和Gamma在努力保持后向和前向兼容性。JUnit 4可以直接運行根據JUNIT3編寫的測試類,而不用任何修改,直接將各測試類的全名傳遞給test runner即可.test runner會根據不同的測試類調用不同的測試框架版本.

          后向兼容性有點麻煩,即在JUNIT3中執行根據JUNIT4寫的測試類,之所以要這樣是因為在一個集成環境如Ecplise中,不需要升級到JUNIT4也可以測試JUNIT4的測試類,從而避免工具IDE的升級。為了讓JUNIT4的測試類在JUNI3中能執行,你需要一個適配類JUnit4TestAdapter封裝JUNIT3的測試類,如下代碼:

          																				public static junit.framework.Test suite() {
            return new JUnit4TestAdapter(AssertionTest.class);    
          }
          																		

          而JAVA方面,JUNIT4一點兼容性都沒有,因為完全依賴于JDK5的新特性,因此不可能在JAVA1.4上面執行JUNIT4。



          Back to top


          還有...

          JUnit 4遠未結束,還有許多需要補充,如文檔,現在不推薦將以前的測試類升級到JUNIT4。當然JUNIT4的開發速度很快,其計劃也很快會實現,JAVA1.4的開發人員仍然可以使用JUNIT3.8,而使用JAVA5的人員可以考慮是否采用JUNIT4了,因為在特性上更適合。



          Back to top


          資源


          下載測試版本
          • JUnit 4 : Download the newest version of JUnit the SourceForge CVS repository; be sure to use the branch tag "Version4."

          原文:http://www.aygfsteel.com/margiex

          posted on 2006-09-22 09:44 阿輝 閱讀(449) 評論(1)  編輯  收藏 所屬分類: junit

          Feedback

          # re: Junit4功能 先睹為快. (譯文) (轉) 2006-09-22 11:09 阿輝

          需要補充的地方

          JUnit 4是一個非常基本的框架,還不是以前版本的升級。JUNIT3的開發人員會發現有些功能沒有。

          最大的特點就是沒有GUI測試界面,當測試正確時是綠色條,而出錯時紅色的,你也可以在Eclipse中集成JUNIT使用,但JUNIT4既沒有AWT也沒有SWING的GUI測試界面;
          另一個讓人吃驚的是失敗(期望錯誤)和錯誤(未預計的異常錯誤)沒有明顯區別,在JUNIT3中開發人員可以區分這兩種情況,而在JUNIT4中不行;
          最后一個特點是JUNIT中沒有用于建立一堆測試類的 suite()方法,取而代之的是,采用變長參數傳遞未知數量的測試給test runner。
          沒有GUI測試界面的確不方便,但其它改變簡化了JUNIT的使用,從當前JUNIT的操作手冊和FAQ的數量就知道,而JUNIT4的文檔將不會需要這么多。

            回復  更多評論   


          My Links

          Blog Stats

          常用鏈接

          留言簿(1)

          隨筆分類

          隨筆檔案

          搜索

          積分與排名

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 东港市| 岫岩| 那曲县| 大英县| 普格县| 轮台县| 普陀区| 浪卡子县| 绥化市| 堆龙德庆县| 新乐市| 龙陵县| 理塘县| 宝丰县| 永川市| 齐河县| 临西县| 保康县| 商都县| 建瓯市| 宜宾市| 酒泉市| 浦城县| 湖南省| 日土县| 和静县| 山丹县| 麻阳| 临西县| 和林格尔县| 建阳市| 建瓯市| 乌拉特中旗| 色达县| 武冈市| 通化市| 罗甸县| 仙桃市| 彩票| 天等县| 镶黄旗|