您的位置:軟件測(cè)試 > 開(kāi)源軟件測(cè)試 > 開(kāi)源單元測(cè)試工具 > junit
有關(guān)Junit的多線程測(cè)試
作者:網(wǎng)絡(luò)轉(zhuǎn)載 發(fā)布時(shí)間:[ 2012/12/11 15:24:23 ] 推薦標(biāo)簽:

testExampleThread()方法實(shí)際上稱(chēng)不上是一個(gè)測(cè)試方法,實(shí)際上,你想使測(cè)試自動(dòng)化,并且不想把檢查結(jié)果輸出到控制臺(tái),但是,這里卻是這樣的,因此,這一點(diǎn)示范了Junit是不支持多線程的。
注意:testExampleThread()方法執(zhí)行三項(xiàng)任務(wù):
1、 打印“Hello,World”;
2、 初始化并起動(dòng)一個(gè)支持打印“Delayed Hello World.”線程;
3、 打印“Goodbye,World”。

    如果你運(yùn)行這個(gè)測(cè)試類(lèi),你會(huì)注意到一些錯(cuò)誤。TextHellWorld()方法像你期望的那樣運(yùn)行和結(jié)束。它沒(méi)有發(fā)出任何有關(guān)線程的異常,但是你卻不會(huì)接受到來(lái)自線程的返回信息。注意,你不會(huì)看到“Delayed Hello World”。為什么?因?yàn)榫程還在激活狀態(tài)的時(shí)候,Junit已經(jīng)執(zhí)行完成。問(wèn)題發(fā)生在下面這行,使線程執(zhí)行結(jié)束的時(shí)候,你的測(cè)試不能反映出它的執(zhí)行結(jié)果。這個(gè)問(wèn)題行是在Junit的TestRunner中。它沒(méi)有被設(shè)計(jì)成搜尋Runnable實(shí)例,并且等待這些線程發(fā)出報(bào)告,它只是執(zhí)行它們并且忽略了它們的存在。因?yàn)檫@個(gè)原因,幾乎不可能在Junit中編寫(xiě)和維護(hù)多線程的單元測(cè)試。

進(jìn)入GroboUtils

    GroboUtils是Matt Albrecht編寫(xiě)的一個(gè)開(kāi)源項(xiàng)目,它的目標(biāo)是擴(kuò)展Java的測(cè)試可能性。GroboUtils被發(fā)布在MIT許可下,這使它可以很友好的包含到其它的開(kāi)源項(xiàng)目中。

Grobo TestingJUnit 子項(xiàng)目

    GroboUtils被列入與同類(lèi)測(cè)試方面有關(guān)的試驗(yàn)的子項(xiàng)目。這篇文章的焦點(diǎn)集中在Grobo TestingJUnit 子項(xiàng)目,它為Junit引入了一個(gè)支持多線程測(cè)試的擴(kuò)展類(lèi)庫(kù)。(這個(gè)子項(xiàng)目還引入了集成測(cè)試和嚴(yán)重錯(cuò)誤的概念,但是這些特征超出了這篇文章所討論的范圍。)

    在GroboTestingJUnit子項(xiàng)目?jī)?nèi)是BroboTestingJUnit-1.1.0-core.jar類(lèi)庫(kù),它包含了MultiThreadedTestRunner和TestRunnable類(lèi),這兩個(gè)類(lèi)是對(duì)Junit進(jìn)行擴(kuò)展處理多線程測(cè)試所必須的。

TestRunnable類(lèi)

    TestRunnalbe類(lèi)擴(kuò)展了junit.framework.Assert類(lèi)并且實(shí)現(xiàn)了java.lang.Runnable接口。你可以在你的測(cè)試類(lèi)內(nèi)定義TestRunnable對(duì)象做為內(nèi)隱類(lèi)。雖然,傳統(tǒng)的線程類(lèi)實(shí)現(xiàn)一個(gè)run()方法,但是你的嵌套TestRunnable類(lèi)必須實(shí)現(xiàn)runTest()方法來(lái)替代run()方法。這個(gè)方法將被MultiThreadedTestRunner類(lèi)在運(yùn)行時(shí)調(diào)用,因此你不應(yīng)該在構(gòu)造器中調(diào)用它。


MultiThreadedTestRunner類(lèi)

    MultiThreadedTestRunner是一個(gè)允許把異步運(yùn)行的線程數(shù)組放入Junit內(nèi)一個(gè)框架。這個(gè)類(lèi)在它的構(gòu)造器中接受一個(gè)TestRunnable實(shí)例的數(shù)組做為參數(shù)。一旦建立了這個(gè)類(lèi)的一個(gè)實(shí)例,它的runTestRunnables()方法應(yīng)該被調(diào)用開(kāi)始執(zhí)行線程測(cè)試。

    和標(biāo)準(zhǔn)的JunitTestRunner不一樣,MultiThreadedTestRunner將等待,直到所有的線程執(zhí)行終止退出。這樣強(qiáng)制Junit在線程執(zhí)行任務(wù)的時(shí)候進(jìn)行等待,從而巧妙的解決了我們前面提出的問(wèn)題。讓我們來(lái)看一下GroboUtils和Junit是怎樣集成的。

編寫(xiě)多線程測(cè)試

    現(xiàn)在把上面例子中的內(nèi)隱類(lèi)擴(kuò)展自net.sourceforge.groboutils.junit.vl.TestRunnable包,我們必須像下面這樣來(lái)重寫(xiě)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);
}
}

    這時(shí),我們?nèi)徊挥脛?chuàng)建工作線程。MultiThreadedTestRunner將在底層做這件事情,你重寫(xiě)runTest()方法來(lái)替實(shí)現(xiàn)run()方法,runTest()方法被后面的MultiThreadedTestRunner類(lèi)調(diào)用———我們自己不會(huì)調(diào)用它。
一旦TestRunnable被定義,我們必須定義新的測(cè)試用例。在我們的testExampleThread()方法中,我們實(shí)例化了幾個(gè)TestRunnable對(duì)象,并且把它們添加到一個(gè)數(shù)組中。然后,示例化MultiThreadedTestRunner類(lèi),把TestRunnable對(duì)象數(shù)組做為參數(shù)傳遞給這人類(lèi)的構(gòu)造子函數(shù),F(xiàn)在,我們有了一個(gè)MultiThreadedTestRunner類(lèi)的實(shí)例,我們可以調(diào)用它的runTestRunnables()方法來(lái)執(zhí)行測(cè)試。

    MultiThreadedTestRunner(和Junit中的TestRunner不一樣)在繼續(xù)執(zhí)行之前,將等待每一個(gè)線程運(yùn)行終止。它也為通過(guò)構(gòu)造器傳遞給它的每個(gè)TestRunnalbe對(duì)象創(chuàng)建工作線程并且調(diào)用異步的start()方法。這意味著你沒(méi)有必要通過(guò)創(chuàng)建你自己的線程來(lái)跳過(guò)這個(gè)障礙———MultiThreadedTestRunner會(huì)為你做這件事。下面是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);
}
}
/**在你的測(cè)試用例中使用MultiThreadedTestRunner,
* MTTR需要一個(gè)TestRunnable對(duì)象做為它的構(gòu)造器的參數(shù)

* MTTR創(chuàng)建以后,調(diào)用runTestRunnables()方法來(lái)運(yùn)行它
*/
public void testExampleThread()
throws Throwable {

//實(shí)例化 TestRunnable 類(lèi)
TestRunnable tr1, tr2, tr3;
tr1 = new DelayedHello("1");
tr2 = new DelayedHello("2");
tr3 = new DelayedHello("3");

//把實(shí)例傳遞給 MTTR
TestRunnable[] trs = {tr1, tr2, tr3};
MultiThreadedTestRunner mttr =
new MultiThreadedTestRunner(trs);
//執(zhí)行MTTR和線程
mttr.runTestRunnables();
}
/**
* 標(biāo)準(zhǔn)的 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);
}
}

    上面的例子中,每個(gè)線程將會(huì)在你發(fā)出測(cè)試指令后,在2到5秒之間向你返回它們的輸出,它們不僅按時(shí)間顯示,而且是以一個(gè)隨機(jī)的順序來(lái)顯示。這個(gè)單元測(cè)試只有所有的線程都執(zhí)行完成后才會(huì)結(jié)束。由于外加了MultiThreadedTestRunner,所以Junit繼續(xù)執(zhí)行測(cè)試用例之前,必須耐心的等待TestRunnables執(zhí)行完成它們的工作,做為可選項(xiàng),你可以為MultiThreadedTestRunner的執(zhí)行分配大的執(zhí)行時(shí)間(這樣以便你脫離線程,而不掛起測(cè)試)。
要編譯運(yùn)行ExampleTest,你必須在你的CLASSPATH環(huán)境變量中指定junit.jar和GroboUtils-2-core.jar兩個(gè)類(lèi)庫(kù)的位置。這樣你會(huì)看到每人線程以隨機(jī)的順序來(lái)輸出 “Delayed Hedllo World”


結(jié)束語(yǔ)

    寫(xiě)一個(gè)多線程的單元測(cè)試不用感到苦腦,GroboUtils類(lèi)庫(kù)為編寫(xiě)多線程的單元測(cè)試提供了一個(gè)清晰簡(jiǎn)單的API接口,通過(guò)把這個(gè)類(lèi)庫(kù)添加到你的工具包中,你可以把單元測(cè)試擴(kuò)展到模擬繁重的WEB網(wǎng)絡(luò)通訊和并發(fā)的數(shù)據(jù)庫(kù)處理,以及對(duì)你的同步方法進(jìn)行壓力測(cè)試。

上一頁(yè)12下一頁(yè)
軟件測(cè)試工具 | 聯(lián)系我們 | 投訴建議 | 誠(chéng)聘英才 | 申請(qǐng)使用列表 | 網(wǎng)站地圖
滬ICP備07036474 2003-2017 版權(quán)所有 上海澤眾軟件科技有限公司 Shanghai ZeZhong Software Co.,Ltd