后,还有个org.jboss.jrunit.TestDriver类,用于表示客户端和服务器端测试的“驱动”。这个类可以产生新的test harness,把客户端和服务器端的test case放在里面跑。这个测试驱动可以通过一个JGroup消息总线与那些test harness进行通讯,从而控制服务器和所有客户端的test case,并从它们那里获得测试结果
逻辑上,运行一个由test runner控制的测试的顺序如下:
(The logical order of a test run as controlled by the test runner is: )
(译注:这个test runner可能是指刚才所说的driver)
1.为每个客户端和服务器端test case生成一个新的test harness
2.等待确认,直至所以test harness创建完毕,它们各自的消息总线也已经启动
3.一旦收到确认,会等待服务器端的test case启动(比如,调用服务器test case的setUp方法)。否则,假如没有收到确认,杀死所以进程,返回出错信息给JUnit。(译注:可见jrunit只是junit的一个扩展,底层还是依赖于junit的实现,比如错误提示)
4.确认服务器端启动完毕后,通知所有的test case(客户端和服务器的)开始运行。否则(如果没有确认信息),对所有test harness发送退出信息。
5.等待客户端test case的结果
6.一旦收到全部客户端返回的结果,通知服务器进行tear down(例如,调用服务器test case的teardown方法)。否则,杀死所以进程返回出错信息给JUnit
7.等待服务器端的测试结果(当然服务器test case要有test方法)
8.处理所有测试结果,提交给JUnit TestResult类,测试结果会以普通Junit测试报告的方式呈现出来。
9.等待服务器关闭的信息,表明服务器已经成功地关闭并清理完资源
10.关闭消息总线和根测试(root test run),返回至Junit的执行线程中。
对于test driver,用户需要进行编码的地方是实现一个继承自org.jboss.jrunit.TestDriver的抽象类,并实现其中的declareTestClasses()方法。在这个方法内部调用TestDriver类的addTestClasses方法,并且指定客户端test case类、客户端的并发数量以及服务器端test case类
基准修饰符(Benchmark Decorator)
JRunit使用基准修饰符来提供除了普通Junit测试结果外的一些数据,称为基准结果
org.jboss.jrunit.decorators.ThreadLocalDecorator(以及其他可以接收线程个数和循环次数(等参数)的修饰符)——指定多少个线程数,会有多少个执行同一个测试的线程被创建。指定多少次循环,会在每个测试实例中,对每个测试方法循环那么多次。比如,如果指定3个线程、10次循环,那么将会有三个线程执行该测试用例(也即创建了三个测试实例),每个测试实例中,会将里面的所以test方法执行10遍。下面是一个相关的例子:
public class SimpleThreadLoopCounter extends TestCase
{
private static int staticCounter = 0;
private static int staticMethodCounter = 0;
private int localCounter = 0;
public static Test suite()
{
return new ThreadLocalDecorator(SimpleThreadLoopCounter.class, 3, 10, 0, true, true);
}
public SimpleThreadLoopCounter()
{
staticCounter++;
}
public void testCounter() throws Exception
{
System.out.println("staticCounter = " + staticCounter);
System.out.println("staticMethodcounter = " + ++staticMethodCounter);
System.out.println("localCounter = " + ++localCounter);
}
}
运行这个例子,后的输出会是:
staticCounter = 3 staticMethodcounter = 30 localCounter = 10
有个问题是关于junit如何处理多个test方法(译注:具体方式在开头已经有所说明)。对于每个test case中的每个test方法,junit都会创建一个新的测试实例来运行这个方法。为了说明这一点,我们复制上面代码的testCounter方法(把复制后的改名为testCounter2),那么在输出结果中后一行变为:
staticCounter = 6 staticMethodcounter = 60 localCounter = 10
(译注:指定了三个线程,junit又为每个测试类创建两个实例,所以总共3×2个,但是对于每一个,它的localCounter 还是10,即执行了10次循环)
JRUnit和修饰符的注意事项:如果numberOfThreads大于1,那ServerTestHarness不会运行。但是numberOfThreads可以拿来模拟同一时刻并发的客户端数量,从这个意义上来说,我认为这不算是个大问题。如果要用ServerTestHarness来这么做,事实上也的确可以产生多个客户端。即时这些客户端不是在一个进程中并发运行,起码也是在各个单独的进程中并发。而能够设定循环变量也是很有必要的,虽然这样会让客户端额外地调用服务器一段时间(或者反复调用)。因此,如果进行远程测试并且要用ThreadLocalDecorator获取基准数据的话,你可以使用下面这个ThreadLocalDecorator的构造器,它的线程数是默认为1的
public ThreadLocalDecorator(Class testClazz, int loops)