我通过为一个标准 Test 装饰上 LoadTest(由 TimedTest 装饰)应用了上述规范,清单 4 显示了其结果。
清单 4. 经装饰的负载和时限测试
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() 方法运行 10 次(每隔 100 毫秒启动一个线程),且每个线程必须在 2 秒内完成,否则整个测试场景将失败。
使用注意
尽管 JUnitPerf 是一个性能测试框架,但也要先大致估计一下测试要设定的性能指数。这是由于所有由 JUnitPerf 装饰的测试都通过 JUnit 框架运行,所以存在额外的消耗,特别是在利用 fixture 时。由于 JUnit 本身用一个 setUp 和一个 tearDown() 方法装饰所有测试样例,所以要在测试场景的整个上下文中考虑执行时间。
相应地,我经常创建使用我想要的 fixture 逻辑的测试,但也会运行一个空白测试来确定性能指数基线。这是一个大致的估计,但它必须作为基线添加到任何想要的测试限制中。
例如,如果运行一个由 fixture 逻辑(使用 DbUnit)装饰的空白测试用时 2.5 秒,那么您想要的所有测试限制都应将这一额外时间考虑在内 —— 这可以从清单 5 中的基准测试中看到:
清单 5. JUnitPerf 基准测试
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");
}
}
请注意,清单 5 的测试样例 testNothing() 什么都没做。其惟一的目的是确定运行 setUp() 方法(当然,该方法也通过 DbUnit 设置了一个数据库)的总时间。
也请记住,测试时间将依赖于机器的配置而变化,同时也依赖于在执行 JUnitPerf 测试时运行的东西而变化。我经常发现,将 JUnitPerf 测试放到它们自己的分类中有助于将它们同标准测试隔离开。这意味着,在运行一个测试时不必每次都运行 JUnitPerf 测试,例如在一个 CI 环境中签入代码。我也会创建特定的 Ant 任务,从而只在精心策划的将性能测试考虑在内的场景或环境中运行这些测试。
试试吧!
用 JUnitPerf 进行性能测试无疑是一门严格的科学,但在开发生命周期的早期,这是确定和监控应用程序代码的低端性能的方式。另外,由于它是一个基于装饰器的 JUnit 扩展框架,所以可以很容易地用 JUnitPerf 装饰现有的 JUnit 测试。
想想您已经花了这么多时间来担心应用程序在负载下会怎样执行。用 JUnitPerf 进行性能测试可以为您减少担忧并节省时间,同时也确保了应用程序代码的质量。