1.单元测试中遇到的问题
1.程序运行是否正确?
2. 程序多线程下正确性如何?
3. 如何测试程序的性能?
4. 当有多个方案可以选择时,技术上如何比较不同方案的性能?
对于第1种情况,junit就可以满足需求,对于2,3,4种情况,就必须采用多线程并发测试并进行分析。
2.Punit概述
p-unit 是一款开放源码的性能测试框架,和 JUnit 不同,JUnit 关注的是测试案例的正确性,而 p-unit 不仅关注测试案例的正确性,还收集测试案例的性能参数,默认情况下,p-unit 收集测试案例的时间和内存消耗情况,可以产生文件,图片,和 PDF 格式的报表。此外,p-unit 还支持参数化测试,多线程测试以及不同 Java 虚拟机性能之间的比较。
3.Punit特点
* 多线程支持:同一个测试案例可以单线程执行,也可以多线程执行,测试案例开发者只需写一套测试案例。
* 参数化测试案例:很多测试案例,需要测试同一功能在不同数量级上的性能表现。
* 不同虚拟机性能测试:只需指定虚拟机路径,即可测试同一个测试案例在不同虚拟机上的表现,报表上可以非常直观显示性能差别。
* 事件机制构架:punit 是基于事件机制构架的,如果用户想定制报表,只需实现事件响应器,并注册该响应器到 punit 核心即可。
4.punit与junit4
punit也支持junit4版本,支持的元标签如下
* @Test(expected = SomeException.class, checkMethod = "someMethod")
* @Before
* @After
* @BeforeClass
* @AfterClass
对于junit4,必须在main()中加上
runner.setConvention(new AnnotationConvention());
5.Check方法
对于一些测试函数,在执行之前,必须检查一个执行条件是否满足,我们可以通过以"check_"为前缀来定义函数名,比如
@Test(checkMethod="checkTestAdd")
例子:
private Vector _vector = new Vector();
@Test(checkMethod="checkAdd")
public void testAdd() {
_vector.add(new Object());
}
public void checkAdd() {
Assert.areEquals(10, _vector.size());
}
6.单线程执行、多线程执行、多执行嚣执行
单线程执行
指整个testsuit由一个线程来完成。
假设现在有两个测试类组成一个testsuit,每个方法睡眠5秒,则整个方法2 * 4 * 5 = 40 秒.
多执行器执行
指整个testsuit由多个线程来完成。
假设现在有两个测试类组成一个testsuit,每个方法睡眠5秒,一个线程执行整个方法2 * 4 * 5 = 40 秒. 如果采用多执行器执行,则多个执行器会同时执行testsuit中的多个test类。
public static void main(String[] args) {
SoloRunner runner = new SoloRunner();
runner.setExecutorPool(new ExecutorPoolImpl(2));
runner.run(TestSuite.class);
}
多线程执行
多线程执行是指同一个方法同时多少个线程执行。
多线程执行只需要把SoloRunner转换成ConcurrentRunner即可。
new SoloRunner().run(MyTest.class);
new ConcurrentRunner().run(MyTest.class);
默认ConcurrentRunner 建立10个线程执行test方法。可以通过构造函数ConcurrentRunner(int threadCount)设置并发线程数。如果针对不同的方法,需要采用不同的并发线程测试,可以继承Concurrent 接口来实现。
7.TestSuite和Test类
对于TestSuite和Test类,一般调用过程如下
# 调用 setUp()
# 调用测试函数
# 调用tearDown()
注意setUp 和 tearDown的执行时间也被包含到了性能测试中。如果你不想将这段时间统计进去,则需要继承 p-unitTest接口,包括
# 调用 setUpBeforeWatchers.
# i调用 setAfterWatchers.
# 调用 测试方法
# 调用 tearDownBeforeWatchers.
# 调用 tearDownAfterWatchers.
你可以将setUp 和 tearDown的代码写到the setUpBeforeWatchers和 tearDownAfterWatchers中。
8.记录时间和内存消费
punit通过"watcher"来记录内存和时间消耗。punit也支持用户自定义的watcher。用户继承Watcher 接口并注册到punit的runner上即可。时间观察器是默认的。如果需要观察内存消耗,则通过如下代码添加:
runner.methodRunner().addWatcher(new MemoryWatcher());
9.Image/PDF 报表
punit除了支持控制台、文本输出方式,也支持image/pdf输出方式。通过添加如下代码即可
Runner runner = new SoloRunner();
// 支持文本输出
runner.addEventListener(new FileLogger());
// 支持对TestSuite的image输出
runner.addEventListener(new TestSuiteReporter(new ImageRender()));
// 支持以image形式的Overview输出
runner.addEventListener(new OverviewReporter(new PDFRender()));
Image/PDF 报表输出有三种粒度- Overview/TestSuite/TestClass.
# Overview - 所有的测试数据以一张图输出
# TestSuite - 一个testsuite以一张图输出
# TestClass - 一个test类以一张图输出
报表文件默认存放在result目录中。
10.参数化测试
性能测试,不同于单元测试,经常要求测试不同数量级在同一个测试场景中的表现。比如nserting 1000/10000/100000 objects 到 java.util.ArrayList中的性能。
p-unit 支持将参数传给测试方法,测试案例需要实现 p-unit 的 parameterizable 接口,该接口的主要方法是返回一组参数列表,这组列表的参数将会一一传给测试方法。
例
public class ParamTestClass implements Parameterized {
public static void main(String[] args) {
new SoloRunner().run(ParamTestClass.class);
}
public Parameter[] parameters() {
//定义了二个参数实例
return new Parameter[] { new ParameterImpl(10), new ParameterImpl(20) };
}
public void testA(ParameterImpl param) {
System.out.println("testA count = " + param.count()); //$NON-NLS-1$
SampleUtil.doSomething();
}
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);
}
}
}
测试结果
testA count = 10
testA(10) - [131.540134ms]
testA count = 20
testA(20) - [297.562446ms]
参考文献
1.punit官方网站 .
2.认识 p-unit : 一款开源的性能测试工具. http://www.ibm.com/developerworks/cn/java/j-lo-punit/
阅读(1732) | 评论(0) | 转发(0) |