Junit如何進行多線程測試

      網友投稿 1426 2022-05-30

      Junit和許多開源軟件項目集成在一起,但是Junit執行多線程的單元測試有一些問題。這篇文章介紹Junit的一個擴展類庫―――GroboUtils,這個類庫被設計為來解決這些問題,并且使在Junit中進行單元測試成為可能。對Junit和線程有一個基本的理解是有好處的,但對于本篇文章的讀者來說不是必需的。

      介紹

      如果你已經在一個開源的Java項目上工作,或者讀了許多有關“極限編程”和其它“快速開發模式”的書籍,那么,你很有可能已經聽說過有關Junit的事情。它是由Erich?Gamma和Kent?Beck編寫的,Junit是一個Java的自動測試的框架,它允許你為你的軟件定義的“單元測試”―――不管是測試程序還是功能代碼,通常都是基于方法調用方法的。

      Junit能在很多方面幫助你的開發團隊―――在一些文章中已經包含了很多這方面的介紹。但從一個開者到另一個開發者,Junit實際上只專箸于兩件事:

      1、它強制你使用自己的代碼。你的測試代碼只是作為你的產品代碼的客戶端,從客戶端的描述所獲得的對你的軟件的了解,能夠幫助你標識出在API中的錯誤以及怎樣改進代碼,使其最終達到可以使用的目的。

      2、它會給你對軟件中改變帶來信心,如果你的測試用例被中斷,你就是立刻知道錯誤。在一天工作結束的時候,如果測試提示是綠色的,則代碼是正確,你可以自信的檢查它。

      但是Junit不是解決所有軟件測試中問題,第三方的擴展類庫,例如HttpUnit,JwebUnit,XMLUnit等,已經認識到這些框架中不足,并且通過添加功能彌補不足,這些不足之一就是Junit不包含多線程的單元測試。

      在這篇文章中,我們會看到一個很少有人知道的解決這個問題的擴展類庫。我們通過建立Junit框架開始,并且運行一個例子來展示Junit在線程沒試中的不足。在我們認識了Junit在線程測試方面的不足之后,我們通過一個使用GroboUtils框架的例子來討論GroboUnitls

      線程回顧

      對于那些不熟悉線程的人來說,在這一點上是非常不安的(一點都不夸大),離開你的系統,我們將對線做一個簡單的介紹。線程允許你的軟件有多個任務,也就是說可以同時可做兩件事情。

      在Khalid?Mugal和Rolf?Rasmussen的書(A?Programmer's?Guide?to?Java?Certification)中,對線程做了下面這樣的簡短描述:

      一個線程是一個程序中的可執行單元,它是被獨立執行的。在運行時,在程序中的線程

      有一個公共的內存空間,因此,能夠共享數據和代碼;也就是說,它們是輕量級的。它

      也共享正在運行程序的進程。

      Java?線程使運行時環境異步,它允許不同的任務同時被執行。(p.272)

      在web應用程序中,許多用戶可能同時發請求給你的軟件。當你寫單元測試對你的代碼進行壓力測試時,你需要模擬許多并發事件,如果你在開發健壯的中間件,這樣做是尤其重要的。對于這些組件,使用線程測試是一個好的想法。

      不幸的是,Junit在這方面是不足的。

      有關Junit和多線程測試的問題

      如果你想驗證下列代碼,你需要下載并安裝Junit。按著指示去做,以便能夠在Junit的網站能夠找到它。不要過分追求細節,我們將簡要的介紹Junit是怎樣工作的。要寫一個Junit的測試,你必須首先創建一個擴展于junit.framework.TestCase(Juint中的基本測試類)的測試類。

      Main()方法和suite()方法被用啟動測試。無論是從命令行還是IDE集成開發環境窗口,必須確保junit.jar在你的CLASSPATH環境變量里指定。然后為BadExampleTest.Class類編譯運行下列代碼:

      import?junit.framework.*;

      public?class?BadExampleTest?extends?TestCase?{

      //?For?now,?just?verify?that?the?test?runs

      public?void?testExampleThread()

      throws?Throwable?{

      System.out.println("Hello,?World");

      }

      public?static?void?main?(String[]?args)?{

      String[]?name?=

      {?BadExampleTest.class.getName()?};

      junit.textui.TestRunner.main(name);

      }

      public?static?Test?suite()?{

      return?new?TestSuite(

      BadExampleTest.class);

      }

      }

      運行BadExampleTest來驗證所建立的每一件事情的正確性。一旦,main()被調用,Junit框架將自動的執行任意一個用“test”開關命名的方法。繼續并試著運行測試類。如果你正確的做了每一件事,它應該在輸出窗口打印出“Hello?World”。

      現在,我們要給程序添加一個線程類。我將通過擴展java.lang.Runnable接口來做這件事情。最后,我們將改變策略,并且擴展一個使線程自動創建的類。

      在DelayedHello的構造器中,我們創建一個新的線程并且調用它的start()方法。

      import?junit.framework.*;

      public?class?BadExampleTest?extends?TestCase?{

      private?Runnable?runnable;

      public?class?DelayedHello

      implements?Runnable?{

      private?int?count;

      private?Thread?worker;

      private?DelayedHello(int?count)?{

      this.count?=?count;

      worker?=?new?Thread(this);

      worker.start();

      }

      public?void?run()?{

      try?{

      Thread.sleep(count);

      System.out.println(

      "Delayed?Hello?World");

      }?catch(InterruptedException?e)?{

      e.printStackTrace();

      }

      }

      }

      public?void?testExampleThread()

      throws?Throwable?{

      System.out.println("Hello,?World");???????//1

      Junit如何進行多線程測試

      runnable?=?new?DelayedHello(5000);????????//2

      System.out.println("Goodbye,?World");?????//3

      }

      public?static?void?main?(String[]?args)?{

      String[]?name?=

      {?BadExampleTest.class.getName()?};

      junit.textui.TestRunner.main(name);

      }

      public?static?Test?suite()?{

      return?new?TestSuite(

      BadExampleTest.class);

      }

      }

      testExampleThread()方法實際上稱不上是一個測試方法,實際上,你想使測試自動化,并且不想把檢查結果輸出到控制臺,但是,這里卻是這樣的,因此,這一點示范了Junit是不支持多線程的。

      注意:testExampleThread()方法執行三項任務:

      1、????打印“Hello,World”;

      2、????初始化并起動一個支持打印“Delayed?Hello?World.”線程;

      3、????打印“Goodbye,World”。

      如果你運行這個測試類,你會注意到一些錯誤。TextHellWorld()方法像你期望的那樣運行和結束。它沒有發出任何有關線程的異常,但是你卻不會接受到來自線程的返回信息。注意,你不會看到“Delayed?Hello?World”。為什么?因為線程還在激活狀態的時候,Junit已經執行完成。問題發生在下面這行,使線程執行結束的時候,你的測試不能反映出它的執行結果。這個問題行是在Junit的TestRunner中。它沒有被設計成搜尋Runnable實例,并且等待這些線程發出報告,它只是執行它們并且忽略了它們的存在。因為這個原因,幾乎不可能在Junit中編寫和維護多線程的單元測試。

      進入GroboUtils

      GroboUtils是Matt?Albrecht編寫的一個開源項目,它的目標是擴展Java的測試可能性。GroboUtils被發布在MIT許可下,這使它可以很友好的包含到其它的開源項目中。

      Grobo?TestingJUnit?子項目

      GroboUtils被列入與同類測試方面有關的試驗的子項目。這篇文章的焦點集中在Grobo?TestingJUnit?子項目,它為Junit引入了一個支持多線程測試的擴展類庫。(這個子項目還引入了集成測試和嚴重錯誤的概念,但是這些特征超出了這篇文章所討論的范圍。)

      在GroboTestingJUnit子項目內是BroboTestingJUnit-1.1.0-core.jar類庫,它包含了MultiThreadedTestRunner和TestRunnable類,這兩個類是對Junit進行擴展處理多線程測試所必須的。

      TestRunnable類

      TestRunnalbe類擴展了junit.framework.Assert類并且實現了java.lang.Runnable接口。你可以在你的測試類內定義TestRunnable對象做為內隱類。雖然,傳統的線程類實現一個run()方法,但是你的嵌套TestRunnable類必須實現runTest()方法來替代run()方法。這個方法將被MultiThreadedTestRunner類在運行時調用,因此你不應該在構造器中調用它。

      MultiThreadedTestRunner類

      MultiThreadedTestRunner是一個允許把異步運行的線程數組放入Junit內一個框架。這個類在它的構造器中接受一個TestRunnable實例的數組做為參數。一旦建立了這個類的一個實例,它的runTestRunnables()方法就應該被調用開始執行線程測試。

      和標準的JunitTestRunner不一樣,MultiThreadedTestRunner將等待,直到所有的線程執行終止退出。這樣就強制Junit在線程執行任務的時候進行等待,從而巧妙的解決了我們前面提出的問題。讓我們來看一下GroboUtils和Junit是怎樣集成的。

      編寫多線程測試

      現在把上面例子中的內隱類擴展自net.sourceforge.groboutils.junit.vl.TestRunnable包,我們必須像下面這樣來重寫runTest()方法。

      private?class?DelayedHello

      extends?TestRunnable?{

      private?String?name;

      private?DelayedHello(

      String?name)?{

      this.name?=?name;

      }

      public?void?runTest()?throws?Throwable?{

      long?l;

      l?=?Math.round(2?+?Math.random()?*?3);

      //?Sleep?between?2-5?seconds

      Thread.sleep(l?*?1000);

      System.out.println(

      "Delayed?Hello?World?"?+?name);

      }

      }

      這時,我們全然不用創建工作線程。MultiThreadedTestRunner將在底層做這件事情,你重寫runTest()方法來替實現run()方法,runTest()方法被后面的MultiThreadedTestRunner類調用―――我們自己不會調用它。

      一旦TestRunnable被定義,我們必須定義新的測試用例。在我們的testExampleThread()方法中,我們實例化了幾個TestRunnable對象,并且把它們添加到一個數組中。然后,示例化MultiThreadedTestRunner類,把TestRunnable對象數組做為參數傳遞給這人類的構造子函數。現在,我們有了一個MultiThreadedTestRunner類的實例,我們就可以調用它的runTestRunnables()方法來執行測試。

      MultiThreadedTestRunner(和Junit中的TestRunner不一樣)在繼續執行之前,將等待每一個線程運行終止。它也為通過構造器傳遞給它的每個TestRunnalbe對象創建工作線程并且調用異步的start()方法。這就意味著你沒有必要通過創建你自己的線程來跳過這個障礙―――MultiThreadedTestRunner會為你做這件事。下面是ExampleTest的最終版:

      import?junit.framework.*;

      import?net.sourceforge.groboutils.junit.v1.*;

      public?class?ExampleTest?extends?TestCase?{

      private?TestRunnable?testRunnable;

      private?class?DelayedHello

      extends?TestRunnable?{

      private?String?name;

      private?DelayedHello(

      String?name)?{

      this.name?=?name;

      }

      public?void?runTest()?throws?Throwable?{

      long?l;

      l?=?Math.round(2?+?Math.random()?*?3);

      //?Sleep?between?2-5?seconds

      Thread.sleep(l?*?1000);

      System.out.println(

      "Delayed?Hello?World?"?+?name);

      }

      }

      /**在你的測試用例中使用MultiThreadedTestRunner,

      *?MTTR需要一個TestRunnable對象做為它的構造器的參數

      *?MTTR創建以后,調用runTestRunnables()方法來運行它

      */

      public?void?testExampleThread()

      throws?Throwable?{

      //實例化?TestRunnable?類

      TestRunnable?tr1,?tr2,?tr3;

      tr1?=?new?DelayedHello("1");

      tr2?=?new?DelayedHello("2");

      tr3?=?new?DelayedHello("3");

      //把實例傳遞給?MTTR

      TestRunnable[]?trs?=?{tr1,?tr2,?tr3};

      MultiThreadedTestRunner?mttr?=

      new?MultiThreadedTestRunner(trs);

      //執行MTTR和線程

      mttr.runTestRunnables();

      }

      /**

      *?標準的?main()?和?suite()?方法

      */

      public?static?void?main?(String[]?args)?{

      String[]?name?=

      {?ExampleTest.class.getName()?};

      junit.textui.TestRunner.main(name);

      }

      public?static?Test?suite()?{

      return?new?TestSuite(ExampleTest.class);

      }

      }

      上面的例子中,每個線程將會在你發出測試指令后,在2到5秒之間向你返回它們的輸出,它們不僅按時間顯示,而且是以一個隨機的順序來顯示。這個單元測試只有所有的線程都執行完成后才會結束。由于外加了MultiThreadedTestRunner,所以Junit繼續執行測試用例之前,必須耐心的等待TestRunnables執行完成它們的工作,做為可選項,你可以為MultiThreadedTestRunner的執行分配最大的執行時間(這樣以便你脫離線程,而不掛起測試)。

      要編譯運行ExampleTest,你必須在你的CLASSPATH環境變量中指定junit.jar和GroboUtils-2-core.jar兩個類庫的位置。這樣你就會看到每人線程以隨機的順序來輸出 “Delayed?Hedllo?World”

      結束語

      寫一個多線程的單元測試不用感到苦腦,GroboUtils類庫為編寫多線程的單元測試提供了一個清晰簡單的API接口,通過把這個類庫添加到你的工具包中,你就可以把單元測試擴展到模擬繁重的WEB網絡通訊和并發的數據庫處理,以及對你的同步方法進行壓力測試。

      更多面試題請狠狠的點擊 下載

      junit 任務調度 多線程

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:程序員的修仙之路——“設計模式之道”!
      下一篇:linux常見面試題
      相關文章
      偷自拍亚洲视频在线观看| 亚洲日韩国产精品乱-久| 亚洲粉嫩美白在线| 亚洲日韩中文字幕| 亚洲男人天堂av| 亚洲av色影在线| 久久久久久久久亚洲| 亚洲欧洲国产精品香蕉网| 国产亚洲成归v人片在线观看| 亚洲一区精品伊人久久伊人| 国产精品亚洲一区二区三区在线观看| 亚洲GV天堂无码男同在线观看| 亚洲真人无码永久在线观看| 亚洲一区二区三区成人网站| 亚洲自偷自偷在线成人网站传媒 | 在线亚洲97se亚洲综合在线| 中文字幕亚洲日韩无线码| 亚洲精品国产va在线观看蜜芽| 蜜臀亚洲AV无码精品国产午夜.| 亚洲av无码一区二区三区天堂| 色欲aⅴ亚洲情无码AV蜜桃| 亚洲av无码成人影院一区| 亚洲av无码av在线播放| 亚洲成年人啊啊aa在线观看| 亚洲人成网站在线观看青青| 在线播放亚洲第一字幕| 亚洲成AV人片在线观看| 亚洲AV无码久久精品狠狠爱浪潮| 亚洲国产综合精品中文第一区| 亚洲免费在线播放| 亚洲精品白色在线发布| 亚洲人成电影网站| 亚洲色成人网站WWW永久四虎| 亚洲丁香婷婷综合久久| 国产亚洲综合视频| 国产亚洲精品精品国产亚洲综合| 精品亚洲一区二区| 亚洲综合成人网在线观看| 亚洲国产成人综合| 亚洲精品无码久久久久牙蜜区| 婷婷亚洲综合五月天小说在线 |