小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

追求代碼質(zhì)量: 用 JUnitPerf 進(jìn)行性能測(cè)試

 bananarlily 2014-05-22

在應(yīng)用程序的開發(fā)中,驗(yàn)證應(yīng)用程序的性能幾乎總處于次要的地位。請(qǐng)注意,我強(qiáng)調(diào)的是驗(yàn)證 應(yīng)用程序的性能。應(yīng)用程序的性能總是 首要考慮的因素,但開發(fā)周期中卻很少包含對(duì)性能的驗(yàn)證。

由于種種原因,性能測(cè)試常被延遲到開發(fā)周期的后期。以我的經(jīng)驗(yàn),企業(yè)之所以在開發(fā)過程中不包含性能測(cè)試是因?yàn)?,他們不知道?duì)于正在進(jìn)行開發(fā)的應(yīng)用程序要期待什么。提出了一些(性能)指數(shù),但這些指數(shù)是基于預(yù)期負(fù)載提出的。

發(fā)生下列兩種情況之一時(shí),性能測(cè)試就成為頭等大事:

  • 生產(chǎn)中出現(xiàn)顯而易見的性能問題。
  • 在同意付費(fèi)之前 ,客戶或潛在客戶詢問有關(guān)性能指數(shù)的問題。

本月,我將介紹兩種簡(jiǎn)單的性能測(cè)試技術(shù),在上述兩種情況中的任何一種發(fā)生前進(jìn)行測(cè)試。

改進(jìn)代碼質(zhì)量

別錯(cuò)過 Andrew 的 討論論壇,里面有關(guān)于代碼語法、測(cè)試框架以及如何編寫專注于質(zhì)量的代碼的幫助。

用 JUnitPerf 進(jìn)行測(cè)試

在軟件開發(fā)的早期階段,使用 JUnit 很容易確定基本的低端性能指數(shù)。JUnitPerf 框架能夠?qū)y(cè)試快速地轉(zhuǎn)化為簡(jiǎn)單的負(fù)載測(cè)試,甚至壓力測(cè)試。

可使用 JUnitPerf 創(chuàng)建兩種測(cè)試類型:TimedTestLoadTest。這兩種類型都基于 Decorator 設(shè)計(jì)模式并利用 JUnit 的 suite 機(jī)制。TimedTest 為測(cè)試樣例創(chuàng)建一個(gè)(時(shí)間)上限 —— 如果超過這個(gè)時(shí)間,那么測(cè)試失敗。LoadTest 和計(jì)時(shí)器一起運(yùn)行,它通過運(yùn)行所需的次數(shù)(時(shí)間間隔由配置的計(jì)時(shí)器控制),在一個(gè)特定的測(cè)試用例上創(chuàng)建一個(gè)人工負(fù)載。

回頁首

恰當(dāng)?shù)臅r(shí)限測(cè)試

JUnitPerf TimedTest 讓您可以編寫有相關(guān)時(shí)間限制的測(cè)試 —— 如果超過了該限度,就認(rèn)為測(cè)試是失敗的(即便測(cè)試邏輯本身實(shí)際上是成功的)。在測(cè)試對(duì)于業(yè)務(wù)致關(guān)重要的方法時(shí),時(shí)限測(cè)試相比其他測(cè)試來說,在確定和監(jiān)控性能指數(shù)方面很有幫助。甚至可以測(cè)試得更加細(xì)致一些,可以測(cè)試一系列方法來確保它們滿足特定的時(shí)間限制。

例如,假設(shè)存在一個(gè) Widget 應(yīng)用程序,其中,特定的對(duì)于業(yè)務(wù)致關(guān)重要的方法(如 createWidget())是嚴(yán)格的性能限制的測(cè)試目標(biāo)。假設(shè)需要對(duì)執(zhí)行該 create() 方法的功能方面進(jìn)行性能測(cè)試。這通常會(huì)由不同的團(tuán)隊(duì)使用不同的工具在開發(fā)周期的后期加以確定,這通常不能指出精確的方法。但假設(shè)決定選擇早期經(jīng)常測(cè)試 方法取而代之。

創(chuàng)建 TimedTest 首先要?jiǎng)?chuàng)建一個(gè)標(biāo)準(zhǔn)的 JUnit 測(cè)試。換言之,將對(duì) TestCase 或其派生類進(jìn)行擴(kuò)展,并編寫一個(gè)以 test 開頭的方法,如清單 1 所示:

清單 1. 簡(jiǎn)單的 widget 測(cè)試
public class WidgetDAOImplTest extends TestCase {	
 private WidgetDAO dao;

 public void testCreate() throws Exception{
  IWidget wdgt = new Widget();
  wdgt.setWidgetId(1000);
  wdgt.setPartNumber("12-34-BBD");  
  try{
   this.dao.createWidget(wdgt);
  }catch(CreateException e){
   TestCase.fail("CreateException thrown creating a Widget");
  }	    
 }

 protected void setUp() throws Exception {       
  ApplicationContext context = 
   new ClassPathXmlApplicationContext("spring-config.xml");      
  this.dao = (WidgetDAO) context.getBean("widgetDAO");      
 }   	
}

由于 JUnitPerf 是一個(gè)基于裝飾器的框架,為了真正地駕馭它,必須提供一個(gè) suite() 方法并將現(xiàn)有的測(cè)試裝飾以 TimedTest。TimedTestTest 和執(zhí)行該測(cè)試的最大時(shí)間量作為參數(shù)。

也可以選擇傳入一個(gè) boolean 標(biāo)志作為第三個(gè)參數(shù)(false),這將導(dǎo)致測(cè)試快速失敗 —— 意味著如果超過最大時(shí)間,JUnitPerf 將立即 迫使測(cè)試失敗。否則,測(cè)試樣例將完整運(yùn)行,然后失敗。區(qū)別很微妙:在一個(gè)失敗的樣例中,不帶可選標(biāo)志運(yùn)行測(cè)試可以幫您了解運(yùn)行總時(shí)間。傳入 false 值卻意味著得不到運(yùn)行總時(shí)間。

例如,在清單 2 中,我在運(yùn)行 testCreate() 時(shí)設(shè)定了一個(gè)兩秒鐘的上限。如果執(zhí)行總時(shí)間超過了這個(gè)時(shí)間,測(cè)試樣例將失敗。由于我并未傳入可選的 boolean 參數(shù),該測(cè)試將完整運(yùn)行,而不管運(yùn)行會(huì)持續(xù)多久。

清單 2. 為生成 TimedTest 而實(shí)現(xiàn)的 suite 方法
public static Test suite() {
 long maxElapsedTime = 2000; //2 seconds 
 Test timedTest = new TimedTest(
   new WidgetDAOImplTest("testCreate"), maxElapsedTime);
 return timedTest;    			
}

此測(cè)試通常在 JUnit 框架中運(yùn)行 —— 現(xiàn)有的 Ant 任務(wù)、Eclipse 運(yùn)行器等等,會(huì)像運(yùn)行任何其他 JUnit 測(cè)試一樣運(yùn)行這個(gè)測(cè)試。惟一的不同是,該測(cè)試將發(fā)生在計(jì)時(shí)器的上下文中。

回頁首

過度的負(fù)載測(cè)試

與在測(cè)試場(chǎng)景中驗(yàn)證一個(gè)方法(或系列方法)的時(shí)間限制正好相反,JUnitPerf 也方便了負(fù)載測(cè)試。正如在 TimedTest 中一樣,JUnitPerf 的 LoadTest 也像裝飾器一樣運(yùn)行,它通過將 JUnit Test 和額外的線程信息綁定起來,從而模擬負(fù)載。

使用 LoadTest,可以指定要模擬的用戶(線程)數(shù)量,甚至為這些線程的啟動(dòng)提供計(jì)時(shí)機(jī)制。JUnitPerf 提供兩類 TimerConstantTimerRandomTimer。通過為 LoadTest 提供這兩類計(jì)時(shí)器,可以更真實(shí)地模擬用戶負(fù)載。如果沒有 Timer,所有線程都會(huì)同時(shí)啟動(dòng)。

清單 3 是用 ConstantTimer 實(shí)現(xiàn)的含 10 個(gè)模擬用戶的負(fù)載測(cè)試:

清單 3. 為生成負(fù)載測(cè)試而實(shí)現(xiàn)的 suite 方法
public static Test suite() {
 int users = 10;
 Timer timer = new ConstantTimer(100);		
 return new LoadTest(
  new WidgetDAOImplTest("testCreate"), 
    users, timer);		
}

請(qǐng)注意,testCreate() 方法運(yùn)行 10 次,每個(gè)線程間隔 100 毫秒啟動(dòng)。未設(shè)定時(shí)間限制 —— 這些方法完整運(yùn)行,如果其中任何的方法執(zhí)行失敗,JUnit 會(huì)相應(yīng)地報(bào)告失敗。

回頁首

用樣式進(jìn)行裝飾

裝飾器并不局限于單個(gè)的裝飾物。例如,在 Java? I/O 中,可以為 FileInputStream 裝飾上一個(gè)帶 BufferedReaderInputStreamReader(只要記?。?code>BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream("infilename"), "UTF8")))。

裝飾可以有多個(gè)層次,JUnitPerf 的 TimedTestLoadTest 也是一樣。當(dāng)這兩個(gè)類彼此裝飾時(shí),將導(dǎo)致一些強(qiáng)制的測(cè)試場(chǎng)景,例如像這樣的場(chǎng)景:在一項(xiàng)業(yè)務(wù)中放置了負(fù)載并應(yīng)用了時(shí)間限制?;蛘?,我們可以僅僅將之前的兩個(gè)測(cè)試場(chǎng)景以如下方式結(jié)合起來:

  • testCreate() 方法中放置一項(xiàng)負(fù)載。
  • 規(guī)定每個(gè)線程必須在該時(shí)間限制內(nèi)結(jié)束。

我通過為一個(gè)標(biāo)準(zhǔn) Test 裝飾上 LoadTest(由 TimedTest 裝飾)應(yīng)用了上述規(guī)范,清單 4 顯示了其結(jié)果。

清單 4. 經(jīng)裝飾的負(fù)載和時(shí)限測(cè)試
public static Test suite() {
 int users = 10;
 Timer timer = new ConstantTimer(100);
 long maxElapsedTime = 2000; 	 
 return new TimedTest(new LoadTest(
   new WidgetDAOImplTest("testCreate"), users, timer), 
     maxElapsedTime);  		
}

正如您所看到的那樣,testCreate() 方法運(yùn)行 10 次(每隔 100 毫秒啟動(dòng)一個(gè)線程),且每個(gè)線程必須在 2 秒內(nèi)完成,否則整個(gè)測(cè)試場(chǎng)景將失敗。

回頁首

使用注意

盡管 JUnitPerf 是一個(gè)性能測(cè)試框架,但也要先大致估計(jì)一下測(cè)試要設(shè)定的性能指數(shù)。這是由于所有由 JUnitPerf 裝飾的測(cè)試都通過 JUnit 框架運(yùn)行,所以就存在額外的消耗,特別是在利用 fixture 時(shí)。由于 JUnit 本身用一個(gè) setUp 和一個(gè) tearDown() 方法裝飾所有測(cè)試樣例,所以要在測(cè)試場(chǎng)景的整個(gè)上下文中考慮執(zhí)行時(shí)間。

相應(yīng)地,我經(jīng)常創(chuàng)建使用我想要的 fixture 邏輯的測(cè)試,但也會(huì)運(yùn)行一個(gè)空白測(cè)試來確定性能指數(shù)基線。這是一個(gè)大致的估計(jì),但它必須作為基線添加到任何想要的測(cè)試限制中。

例如,如果運(yùn)行一個(gè)由 fixture 邏輯(使用 DbUnit)裝飾的空白測(cè)試用時(shí) 2.5 秒,那么您想要的所有測(cè)試限制都應(yīng)將這一額外時(shí)間考慮在內(nèi) —— 這可以從清單 5 中的基準(zhǔn)測(cè)試中看到:

清單 5. JUnitPerf 基準(zhǔn)測(cè)試
public class DBUnitSetUpBenchmarkTest extends DatabaseTestCase {
 private WidgetDAO dao = null;

 public void testNothing(){
  //should be about 2.5 seconds
 }

 protected IDatabaseConnection getConnection() throws Exception {        
  Class driverClass = Class.forName("org.hsqldb.jdbcDriver");
  Connection jdbcConnection = 
   DriverManager.getConnection(
     "jdbc:hsqldb:hsql://127.0.0.1", "sa", "");
  return new DatabaseConnection(jdbcConnection);
 }

 protected IDataSet getDataSet() throws Exception {        
  return new FlatXmlDataSet(new File("test/conf/seed.xml"));
 }

 protected void setUp() throws Exception {
  super.setUp();      
  final ApplicationContext context = 
   new ClassPathXmlApplicationContext("spring-config.xml");      
  this.dao = (WidgetDAO) context.getBean("widgetDAO");      
 }
}

請(qǐng)注意,清單 5 的測(cè)試樣例 testNothing()什么都沒做。其惟一的目的是確定運(yùn)行 setUp() 方法(當(dāng)然,該方法也通過 DbUnit 設(shè)置了一個(gè)數(shù)據(jù)庫)的總時(shí)間。

也請(qǐng)記住,測(cè)試時(shí)間將依賴于機(jī)器的配置而變化,同時(shí)也依賴于在執(zhí)行 JUnitPerf 測(cè)試時(shí)運(yùn)行的東西而變化。我經(jīng)常發(fā)現(xiàn),將 JUnitPerf 測(cè)試放到它們自己的分類中有助于將它們同標(biāo)準(zhǔn)測(cè)試隔離開。這意味著,在運(yùn)行一個(gè)測(cè)試時(shí)不必每次都運(yùn)行 JUnitPerf 測(cè)試,例如在一個(gè) CI 環(huán)境中簽入代碼。我也會(huì)創(chuàng)建特定的 Ant 任務(wù),從而只在精心策劃的將性能測(cè)試考慮在內(nèi)的場(chǎng)景或環(huán)境中運(yùn)行這些測(cè)試。

回頁首

試試吧!

用 JUnitPerf 進(jìn)行性能測(cè)試無疑是一門嚴(yán)格的科學(xué),但在開發(fā)生命周期的早期,這是確定和監(jiān)控應(yīng)用程序代碼的低端性能的極佳方式。另外,由于它是一個(gè)基于裝飾器的 JUnit 擴(kuò)展框架,所以可以很容易地用 JUnitPerf 裝飾現(xiàn)有的 JUnit 測(cè)試。

想想您已經(jīng)花了這么多時(shí)間來擔(dān)心應(yīng)用程序在負(fù)載下會(huì)怎樣執(zhí)行。用 JUnitPerf 進(jìn)行性能測(cè)試可以為您減少擔(dān)憂并節(jié)省時(shí)間,同時(shí)也確保了應(yīng)用程序代碼的質(zhì)量。

參考資料

學(xué)習(xí)

獲得產(chǎn)品和技術(shù)

  • 下載 JUnit:了解 JUnit 4 的新特性。
  • 下載 JUnitPerf:一系列用于測(cè)量性能和可伸縮性的 JUnit 測(cè)試裝飾器。

討論

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多