负载下承受能力测试举例
import com.clarkware.junitperf.*;
import junit.framework.Test;
public class ExampleThroughputUnderLoadTest {
public static Test suite() {
int maxUsers = 10;
long maxElapsedTime = 1500;
Test testCase = new ExampleTestCase("testOneSecondResponse");
Test loadTest = new LoadTest(testCase, maxUsers);
Test timedTest = new TimedTest(loadTest, maxElapsedTime);
return timedTest;
}
public static void main(String[] args) {
junit.textui.TestRunner.run(suite());
}
}
在下面的例子中,测试被颠倒过来了, TimedTest 度量 ExampleTestCase.testOneSecondResponse() 方法的执行时间。然后LoadTest 中嵌套了TimedTest 来仿效10 个并发用户执行ExampleTestCase.testOneSecondResponse() 方法。如果某个用户的执行时间超过了1 秒则视为不通过。
负载下响应时间测试举例
import com.clarkware.junitperf.*;
import junit.framework.Test;
public class ExampleResponseTimeUnderLoadTest {
public static Test suite() {
int maxUsers = 10;
long maxElapsedTime = 1000;
Test testCase = new ExampleTestCase("testOneSecondResponse");
Test timedTest = new TimedTest(testCase, maxElapsedTime);
Test loadTest = new LoadTest(timedTest, maxUsers);
return loadTest;
}
public static void main(String[] args) {
junit.textui.TestRunner.run(suite());
}
}
性能测试套件
下面的测试用例例子中把 ExampleTimedTest 和 ExampleLoadTest 结合在一个测试套件中,这样就可以自动地执行所有相关的性能测试了:
Example Performance Test Suite
import junit.framework.Test;
import junit.framework.TestSuite;
public class ExamplePerfTestSuite {
public static Test suite() {
TestSuite suite = new TestSuite();
suite.addTest(ExampleTimedTest.suite());
suite.addTest(ExampleLoadTest.suite());
return suite;
}
public static void main(String[] args) {
junit.textui.TestRunner.run(suite());
}
}
编写有效的 JUnitPerf 测试
Timed Tests
Waiting Timed Tests
默认情况下 TimedTest 测试中如果实际测试时间超过了预期时间则继续执行JUnit 的测试。这种 waiting timed test 总是允许 JUnit 测试累积所有的测试结果,直到测试完成并且检查完所有的测试结果。
如果测试执行中等待测试完毕的用例直接或间接地派生多个线程,那么此次测试只有等到所有的线程执行完毕才会返回到 timed test 中。另外一方面该测试将无限期地等待。一般来说,单元测试应该等待所有派生的线程执行完毕,例如使用 Thread.join() 方法,以便准确地判断结果。
Non-Waiting Timed Tests
此外, TimedTest 还 提供了一个构造方法,当实际时间超过预期时间时立即表示未通过。这种类型的测试如果执行时间超过了预期的最大时间则不等待测试继续执行完毕。这种类型的测 试比上一种方式更加有效,根据需要这种测试可节约时间,将不再等待程序执行并且立即标识测试未通过。然而,跟上面一种类型不同的是,这种类型的测试如果中 间有测试不通过的话就不继续执行后面的测试了。
Load Tests
Non-Atomic Load Tests
默认情况下,如果 LoadTest 扩展出来的测试直接或间接地派生线程,它不会强制这种线程并发执行(正如在事务中定义的一样)。这种类型的测试假设它扩展的测试在当返回控制时交互地完成。例如如果扩展测试的派生线程和控制返回没有等待派生进程执行完毕,那么扩展测试就假定为一次性地完成了。
而一般来讲,单元测试中为了准确地判断结果,应该等待派生的线程也执行完毕,例如使用 Thread.join() 方法然而在某些情况下并不是一定要这样的。例如,对于EJB 分布式的查询结果,应用服务器可能派生一个新的线程去处理这个请求。如果新的线程在同一个线程组中运行 decorated 测试(默认情况),那么一个非原子的压力测试仅仅等待压力测试直接派生的线程执行完毕而新生成的线程则会被忽略掉。
总之,非原子压力测试仅仅等待压力测试中直接派生的线程执行完毕来模仿多个并发用户。
Atomic Load Tests
如果多个线程规定一个 decorated 测试成功地执行,这就意味着只有所有 decorated 测试中的线程执行完毕这个 decorated 测试才被认为是完成了。可以使用 setEnforceTestAtomicity(true) 来强迫执行这种测试()。这将有效地促使这种测试等待属于 decorated 测试的线程组的所有线程执行完毕。原子性压力测试也会把任何过早退出的线程当成是失败。如果一个线程突然崩溃,那么属于同一线程组的其他线程就会立即停止执行。
如果 decorated 测试派生的线程属于同一个线程组,默认情况下线程执行 decorated 测试,这样原子压力测试将无限期地等待派生的线程执行完毕。
总之,原子压力测试将等待所有属于同一线程组的线程执行完毕,压力测试直接派生的线程,来模仿多个用户并发。
局限性
JUnitPerf 已知有以下缺陷:
· TimedTest 返回的时间是测试用例的testXXX() 方法的时间,包括setUp() , testXXX() 和 tearDown() 三个方法的总时间,这是任何测试实例中所能提供的最小的测试粒度。因此期望的时间也应该考虑 set-up 和 tear-down 的运行时间。(译者注:或者可以自己在 JUnit 测试用例使用 System.currentTimeMillis() 方法来计算某个步骤的执行时间)
· JUnitPerf 并不是一个完整的压力和性能测试工具,并且它也不会用来取代其它类似的工具。它仅仅用来编写本地的单元性能测试来帮助开发人员做好重构。
· The performance of your tests can degrade significantly if too many concurrent users are cooperating in a load test. The actual threshold number is JVM specific.
· 在压力测试中如果有太多的用户并发运行则测试情况会越来越糟。应该参照 JVM 的规范来指定用户数。
技术支持
如果您有任何关于 JUnitPerf 的疑问,需要改进的要求,成功的经历或者 bug ,或者当有新的版本发布时得到通知请发 email 给 [email protected] 。您的个人信息不会被公开。
您也可以通过邮件列表( http://groups.yahoo.com/group/junitperf/ )的方式来讨论有关 JUnitPerf 并且在有新的版本发布时收到通知。
捐助
您可以通过购买《 Pragmatic Project Automation 》( http://www.pragmaticprogrammer.com/sk/auto/ )一书的方式支持 JUnitPerf 的继续开发。
培训与指导
可以通过访问站点 http://clarkware.com/courses/TDDWithJUnit.html 了解有关快速地创建测试代码的方法。
这里也提供有关 JUnit 的指导( http://clarkware.com/mentoring.html )来帮助你改进测试。
如果想获得更多的信息请与我联系( mailto:[email protected] )。
许可信息
JUnitPerf is licensed under the BSD License .
感谢
非常感谢 Ervin Varga 在线程健壮性和原子性测试方面给予的帮助。他在这些方面提出使用线程组来捕获和处理线程的异常,此外在 TimeTest 和 TestFactory 中提出了如果执行时间超时则立即标识为失败的实现方式。非常感激他对 JUnitPerf 的亲睐和建议。
翻译
MSN:wyingquan at hotmail dot com 完成时间: 2005-4-19
相关资源及参考文档
· JUnit Primer
Mike Clark, Clarkware Consulting, Inc.
本文简单阐述了如何使用 JUnit 测试框架来编写和运行简单的测试用例及套件。
· Continuous Performance Testing With JUnitPerf
Mike Clark (JavaProNews, 2003)
本文讲解了如何编写 JUnitPerf 测试来不时地检查性能和可测性等情况。
· Test-Driven Development: A Practical Guide
David Astels (Prentice Hall, 2003)
包括一章由本文作者编写的如何使用 JUnitPerf 来持续进行性能测试。
· Java Extreme Programming Cookbook
Eric Burke, Brian Coyner (O'Reilly & Associates, 2003)
其中有一张专门讲述了 JUnitPerf 的用法。
· Java Tools for Extreme Programming: Mastering Open Source Tools Including Ant, JUnit, and Cactus
Richard Hightower, Nicholas Lesiecki (John Wiley & Sons, 2001)
包含一章描述了如何与 HttpUnit 一起使用 JUnitPerf 。