本篇文章為大家展示了開源的性能測(cè)試框架p-unit怎么用,內(nèi)容簡(jiǎn)明扼要并且容易理解,絕對(duì)能使你眼前一亮,通過這篇文章的詳細(xì)介紹希望你能有所收獲。
p-unit 是一款開放源碼的性能測(cè)試框架,和 JUnit 不同,JUnit 關(guān)注的是測(cè)試案例的正確性,而 p-unit 不僅關(guān)注測(cè)試案例的正確性,還收集測(cè)試案例的性能參數(shù),默認(rèn)情況下,p-unit 收集測(cè)試案例的時(shí)間和內(nèi)存消耗情況,可以產(chǎn)生文件,圖片,和 PDF 格式的報(bào)表。此外,p-unit 還支持參數(shù)化測(cè)試,多線程測(cè)試以及不同 Java 虛擬機(jī)性能之間的比較。
p-unit 簡(jiǎn)介
或許我們已經(jīng)習(xí)慣了使用 JUnit 來寫單元測(cè)試來保證代碼質(zhì)量(我也一直這么做),但可能經(jīng)常碰到這樣的問題:
程序多線程下正確性如何?
如何測(cè)試程序的性能?
當(dāng)有多個(gè)方案可以選擇時(shí),技術(shù)上如何比較不同方案的性能?
對(duì)于問題 1,我們或許聽天由命?或是憑借人工分析,或是根據(jù)用戶反饋?很多軟件單線程下的單元測(cè)試覆蓋率相當(dāng)高,從而保證了代碼的健壯性。然而多線程測(cè)試時(shí)常被忽略,這并不代表多線程測(cè)試不重要,相反,修正一個(gè)用戶報(bào)告的多線程 BUG 往往比單線程的要高出很多,因?yàn)闇y(cè)試案例經(jīng)常不是 100% 可重現(xiàn)的。這更要求程序員在開發(fā)階段充分的重視。目前多線程單元測(cè)試力度不夠的一個(gè)重要原因是沒有一個(gè)像 JUnit 那樣易用的測(cè)試工具,另外重復(fù)寫測(cè)試案例往往不被程序員接受。
對(duì)于問題 2,一個(gè)成熟的關(guān)心性能的產(chǎn)品往往有一個(gè)性能測(cè)試平臺(tái)。這個(gè)測(cè)試平臺(tái)應(yīng)該關(guān)注的是測(cè)試業(yè)務(wù)邏輯本身,而無需關(guān)心如何運(yùn)行測(cè)試案例。你是否為寫這樣的測(cè)試平臺(tái)痛苦過?以及花費(fèi)時(shí)間在產(chǎn)生一些直觀的報(bào)表上面?
對(duì)于問題 3,我們往往寫一個(gè)原型來比較不同產(chǎn)品之間的性能,如何比較執(zhí)行速度和內(nèi)存消耗?或是選擇最適合你的虛擬機(jī)?
p-unit 就是這么一款開源的性能測(cè)試軟件,它能幫助你很好的解決上述問題。p-unit 可以:
多線程支持:同一個(gè)測(cè)試案例可以單線程執(zhí)行,也可以多線程執(zhí)行,測(cè)試案例開發(fā)者只需寫一套測(cè)試案例。
參數(shù)化測(cè)試案例:很多測(cè)試案例,需要測(cè)試同一功能在不同數(shù)量級(jí)上的性能表現(xiàn)。
不同虛擬機(jī)性能測(cè)試:只需指定虛擬機(jī)路徑,即可測(cè)試同一個(gè)測(cè)試案例在不同虛擬機(jī)上的表現(xiàn),報(bào)表上可以非常直觀顯示性能差別。
事件機(jī)制構(gòu)架:punit 是基于事件機(jī)制構(gòu)架的,如果用戶想定制報(bào)表,只需實(shí)現(xiàn)事件響應(yīng)器,并注冊(cè)該響應(yīng)器到 punit 核心即可。
多線程執(zhí)行測(cè)試案例
在了解如何多線程執(zhí)行測(cè)試案例之前,我們先了解一下如何利用 p-unit 單線程執(zhí)行測(cè)試案例。不同于 JUnit, p-unit 測(cè)試用例無需繼承任何測(cè)試類或是實(shí)現(xiàn)接口,即可執(zhí)行 test 開始的方法。盡管 JUnit 4 中加入了注釋(Annotation) 的特性,但測(cè)試方法前綴為 "test" 仍然是測(cè)試者們的選。因此如果你的 JUnit 測(cè)試案例遵循的是 test 命名規(guī)則,那么 p-uni t可以兼容運(yùn)行 JUnit 測(cè)試案例。
下面的代碼清單 1 是一個(gè)最為普通的測(cè)試案例:
public class SimpleTestClass { public void setUp() { SampleUtil.doSomething(); } public void tearDown() { SampleUtil.doSomething(); } public void testA() { System.out.println("testA"); SampleUtil.doSomething(); } public void testB() { SampleUtil.doSomething(); } public void testC() { SampleUtil.doSomething(); } } public class SampleUtil { private static Random _random = new Random(); public static void consumeMemory(int length) { byte[] data = new byte[length]; for(int i = 0, j = 0; i < data.length; ++i) { ++j; } } public static void consumeTime(int time) { ThreadUtil.sleepIgnoreInterruption(time); } public static void doSomething() { consumeTime(Math.abs(_random.nextInt()) % 500); consumeMemory(Math.abs(_random.nextInt()) % 100000); } }
這是做為普通的測(cè)試案例,但是注意到這僅僅是一個(gè)測(cè)試案例,不包含其他任何邏輯,這也是 p-unit 追求的業(yè)務(wù)邏輯和測(cè)試運(yùn)行環(huán)境分離的一個(gè)理念。同一個(gè)測(cè)試案例,用戶可以選擇不同的測(cè)試環(huán)境去運(yùn)行,而不是綁定在某一個(gè)特定的測(cè)試軟件工具上。現(xiàn)在我們來看 p-unit 是如何運(yùn)行這個(gè)測(cè)試案例的。你只需要在 main 函數(shù)中寫一行代碼來運(yùn)行它:
清單 2. 單線程運(yùn)行測(cè)試案例
CODE:
清單 3. 單線程運(yùn)行測(cè)試案例結(jié)果
public static void main(String[] args) {
new PUnitSoloRunner().run(SimpleTestClass.class);
}
[solo] Started running samples.SimpleTestClass
samples.SimpleTestClass
testA
testA() - [287.0ms]
testB() - [27.0ms]
testC() - [213.0ms]
total: 3, failures:0 (GREEN) - 2025.0ms
是否和想象中的一樣?下面我們來看如何多線程執(zhí)行這個(gè)測(cè)試案例。或許從上面的例子你已經(jīng)猜到了,在 main 函數(shù)還是只需一句代碼,只用把 PUnitSoloRunner 換成 PUnitConcurrentRunner 即可!
清單 4. 多線程運(yùn)行測(cè)試案例
public static void main(String[] args) { new PUnitConcurrentRunner().run(SimpleTestClass.class); }
清單 5. 多線程運(yùn)行測(cè)試案例結(jié)果
[concurrent] Started running samples.SimpleTestClass samples.SimpleTestClass testA testA testA testA testA testA testA testA testA testA testA() - [405.0ms] testB() - [469.0ms] testC() - [503.0ms] total: 3, failures:0 (GREEN) - 1447.0ms
是否和想象中的一樣?默認(rèn)情況 p-unit 啟動(dòng) 10 個(gè)線程來執(zhí)行,要指定不同的線程數(shù),只需將線程數(shù)做為參數(shù)傳入 PUnitConcurrentRunner 即可。p-unit 甚至支持不同的測(cè)試案例有不同的線程數(shù),這要求測(cè)試案例實(shí)現(xiàn) p-unit 中定義的 Concurrent 接口,該接口的定義為:
清單 6. p-unit Concurrent 接口
CODE:
該接口的意思,相信無需再多做解釋了,返回該測(cè)試案例需要的線程數(shù)。
public interface Concurrent {
public int concurrentCount();
}
quake at 2007-11-21 15:35:48
參數(shù)化測(cè)試案例
性能測(cè)試,不同于單元測(cè)試,經(jīng)常要求測(cè)試不同數(shù)量級(jí)在同一個(gè)測(cè)試場(chǎng)景中的表現(xiàn),JUnit 是一款非常優(yōu)秀的單元測(cè)試工具,但沒覆蓋到這個(gè)方面。比如我們比較類庫 Foo1 的方法 bar() 和類庫 Foo2 的方法 bar() 哪個(gè)更符合自己的應(yīng)用程序,我們需要測(cè)試該函數(shù)在應(yīng)用程序可能的數(shù)量級(jí)的范圍內(nèi)的表現(xiàn)。有經(jīng)驗(yàn)的開發(fā)者知道經(jīng)常碰到在小數(shù)量級(jí) A 更好大數(shù)量級(jí) B 更好的局面,因此全面的測(cè)試對(duì)于代碼的性能理解非常重要,能幫助開發(fā)者做出正確的決定。p-unit 支持將參數(shù)傳給測(cè)試方法,測(cè)試案例需要實(shí)現(xiàn) p-unit 的 parameterizable 接口,該接口的主要方法是返回一組參數(shù)列表,這組列表的參數(shù)將會(huì)一一傳給測(cè)試方法。
清單 7. p-unit 參數(shù)化測(cè)試案例
public class ParamTestClass implements Parameterizable { public static void main(String[] args) { new PUnitSoloRunner().run(ParamTestClass.class); } public Parameter[] parameters() { return new Parameter[] { new ParameterImpl(10), new ParameterImpl(20) }; } public void testA(ParameterImpl param) { SampleUtil.doSomething(); } public void testB(ParameterImpl param) { SampleUtil.doSomething(); } public void testC(ParameterImpl param) { SampleUtil.doSomething(); } public void setUpAfterWatchers(Parameter param) throws Exception { } public void setUpBeforeWatchers(Parameter param) throws Exception { } public void tearDownAfterWatchers(Parameter param) throws Exception { } public void tearDownBeforeWatchers(Parameter param) throws Exception { } static class ParameterImpl implements Parameter { private int _count; ParameterImpl(int count) { _count = count; } public int count() { return _count; } public String toString() { return String.valueOf(_count); } } }
上述代碼的執(zhí)行結(jié)果為:
CODE:
[solo] Started running samples.ParamTestClass
samples.ParamTestClass
testA(10) - [57936.0bytes,447.0ms]
testA(20) - [33128.0bytes,61.0ms]
testB(10) - [24832.0bytes,137.0ms]
testB(20) - [0.0bytes,63.0ms]
testC(10) - [83560.0bytes,468.0ms]
testC(20) - [16528.0bytes,47.0ms]
total: 6, failures:0 (GREEN) 1450.0ms
從上述結(jié)果看出,每個(gè)方法被執(zhí)行了 2 次,每次傳入不同的參數(shù)。多線程運(yùn)行參數(shù)化測(cè)試程序?相信讀者已經(jīng)明白怎么去實(shí)現(xiàn)了,只需將 PUnitSoloRunner 替換成 PUnitConcurrentRunner。
quake at 2007-11-21 15:40:22
運(yùn)行環(huán)境測(cè)試案例
隨著 Java 開源,出現(xiàn)了更多的 Java 運(yùn)行環(huán)境,除了 SUN 的參考實(shí)現(xiàn)外,BEA、IBM 均有自己的 Java 運(yùn)行環(huán)境,更有如 Apache Harmony 的開源運(yùn)行環(huán)境(盡管現(xiàn)在 Apache Harmony 尚不能稱為 Java 運(yùn)行環(huán)境)。運(yùn)行環(huán)境測(cè)試案例,為運(yùn)行環(huán)境開發(fā)者以及選擇運(yùn)行環(huán)境,都能提供一定的幫助。比如說下面的例子就是測(cè)試 java.util.ArrayList 和 java.util.Vector 在兩個(gè)不同運(yùn)行環(huán)境的表現(xiàn)。測(cè)試案例寫法和普通的測(cè)試案例完全一樣,我們只需告訴 p-unit 不同的運(yùn)行環(huán)境的 Java 路徑以及正確的 classpath,然后調(diào)用 runVMs 函數(shù)即可:
清單 9. p-unit 運(yùn)行環(huán)境測(cè)試案例
public static void main(String[] args) { PUnitSoloRunner runner = new PUnitSoloRunner(); runner.addPUnitEventListener(new OverviewReporter(new ImageRender())); runner.runVMs(ListTestClass.class, new VM[] { VMConfig.HARMONY, VMConfig.SUN }); } public class VMConfig { private static String CLASSPATH = " -cp correct_classpath_including_all_jars_and_path"; private static String HARMONY_PATH = "harmony_pathbinjava" + CLASSPATH; private static String SUN_PATH = "sun_pathbinjava" + CLASSPATH; public static VM HARMONY = new VM(HARMONY_PATH, "HARMONY"); public static VM SUN = new VM(SUN_PATH, "SUN"); } public class ListTestClass { private static final int LIST_COUNT = 100000; private static Object element = new Object(); private Random indexGenerator = new Random();; public void testInsertArrayList() { ArrayList arrayList = new ArrayList(LIST_COUNT); insertSequence(arrayList); insertRandom(arrayList); } public void testInsertVector() { Vector vector = new Vector(LIST_COUNT); insertSequence(vector); insertRandom(vector); } public void insertSequence(List list) { for (int i = 0; i < LIST_COUNT; ++i) { list.add(element); } } public void insertRandom(List list) { for (int i = 0; i < LIST_COUNT; ++i) { list.add(indexGenerator .nextInt(LIST_COUNT),element); } } }
筆者使用的 HARMONY 版本在該測(cè)試案例中速度更快,但內(nèi)存消耗更多。
從上面的實(shí)例中我們已經(jīng)看到 p-unit 的輸出結(jié)果的兩種形式,控制臺(tái)和報(bào)表圖片。默認(rèn)情況下,p-unit 將輸出到控制臺(tái)。p-unit 采用事件機(jī)制,在運(yùn)行器的每個(gè)節(jié)點(diǎn)都會(huì)提供通知事件。所有的輸出都是通過注冊(cè)事件響應(yīng)器來實(shí)現(xiàn)的。這也表明了結(jié)果輸出和運(yùn)行器完全隔離,用戶也可以定制自己的報(bào)表。p-unit 有 4 種內(nèi)建輸出,分別為控制臺(tái)、文件、圖片報(bào)表以及 PDF 報(bào)表。上一節(jié)的例子中我們已經(jīng)看到圖片報(bào)表,其代碼為:
清單 10. 添加 p-unit 總體圖片報(bào)表
CODE:
runner.addPUnitEventListener(new OverviewReporter(new ImageRender()));
p-unit 內(nèi)建的報(bào)表有分三種不同的粒度:總體級(jí)別(OverviewReporter),TestSutie 級(jí)別(TestSuiteReporter),以及測(cè)試案例類級(jí)別(TestClassReporter)。這三種級(jí)別都可以輸出圖片格式或是 PDF 格式,因此,總共有六種類型的輸出。上述的代碼就是輸出總體級(jí)別的圖片。由于事件監(jiān)聽器是互相獨(dú)立的,因此你可以既選擇輸出圖片又選擇輸出 PDF 文件,只需再添加事件監(jiān)聽器即可:
清單 11. 添加多個(gè) p-unit 事件監(jiān)聽器
runner.addPUnitEventListener(new OverviewReporter(new ImageRender())); runner.addPUnitEventListener(new OverviewReporter(new PDFRender()));
上述內(nèi)容就是開源的性能測(cè)試框架p-unit怎么用,你們學(xué)到知識(shí)或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識(shí)儲(chǔ)備,歡迎關(guān)注創(chuàng)新互聯(lián)-成都網(wǎng)站建設(shè)公司行業(yè)資訊頻道。
當(dāng)前名稱:開源的性能測(cè)試框架p-unit怎么用-創(chuàng)新互聯(lián)
標(biāo)題網(wǎng)址:http://m.newbst.com/article38/dcshsp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站維護(hù)、云服務(wù)器、網(wǎng)頁設(shè)計(jì)公司、網(wǎng)站收錄、微信小程序、企業(yè)建站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容