如下表所示,在JavaTestHarness中执行的脚本都必须实现Test接口,并且返回一个Status。这两个类都是com.sun.javatest包下面的,因此开发的时候必须引用javatest.jar这个包。但是实际开发的时候,脚本其实和javatest.jar应该是没有任何关系的,我们应该让他们解耦。
package com.sun.demots.tests.bignum; import java.io.PrintWriter; import com.sun.javatest.Status; import com.sun.javatest.Test; import com.sun.demoapi.BigNum; /** * A test for com.sun.demoapi.BigNum.add. * * @test * @sources AddTest.java * @executeClass com.sun.demots.tests.bignum.AddTest */ public class AddTest implements Test { public static void main(String[] args) { PrintWriter err = new PrintWriter(System.err, true); Test t = new AddTest(); Status s = t.run(args, null, err); s.exit(); }
public Status run(String[] args, PrintWriter out, PrintWriter err) { // save error stream to which to write error messages this.err = err;
boolean ok = true;
ok = ok & test("-12345678901234567890", "-12345678901234567890", "-24691357802469135780"); ok = ok & test("-12345678901234567890", "-1234567890", "-12345678902469135780"); […] if (ok) return Status.passed("OK"); else return Status.failed("one or more test cases failed"); } |
1. 自定义脚本的格式
下面设计一种脚本格式,让该脚本与javatest.jar完全没有关系,但是能被harness执行。脚本格式如下:
/** *测试脚本Test1。 *@authorjingping.yi * */ public class Test1 { /** *测试脚本执行时执行的方法。 *@return如果脚本通过,返回true,harness界面中显示绿色; * 如果脚本不通过,返回false,harness界面中显示红色 *@throwsException如果脚本执行过程抛出异常,则脚本异常, * harness界面中显示蓝色 */ public boolean run() throws Exception{ […执行过程…] return false; } } |
如上所示。测试人员只要将测试脚本写在run方法中,然后通过控制返回值true/false或者抛出异常来表示脚本通过/不通过或者执行异常。这种方式和返回Status对象除了没有message,其他的是完全一样的。
2. 实现harness与自定义脚本的中间层
因为harness能处理的还是Status对象,所以我们给仍要给上层返回Status对象。但是下层的脚本只能返回true/false/Exception,所以应该写一个中间层,将true/false/Exception转化成Status对象。这里要用到反射的技术,代码如下:
package com.toast.javatest.script;
import java.io.PrintWriter;
import com.sun.javatest.Status; import com.sun.javatest.Test;
public class ToastExec implements Test { public static void main(String[] args){ PrintWriter out = new PrintWriter(System.out,true); PrintWriter err = new PrintWriter(System.err,true); Test t = new ToastExec(); Status s = t.run(args, err, out); s.exit(); }
/** *要求arg0的第1个参数是完整的带包路径的类名。 */ @Override public Status run(String[] arg0, PrintWriter arg1, PrintWriter arg2) { Status s = null; Boolean res = false; //脚本的类名和方法名 String className = arg0[0]; String methodName = "run"; //使用反射的方式调用脚本的run方法 try { Class executeClass = Class.forName(className); java.lang.reflect.Method runMethod = executeClass.getMethod(methodName); res = (Boolean) runMethod.invoke(executeClass.newInstance());
//将执行结果,返回给Harness if (res) s = Status.passed("执行成功"); else s = Status.failed("执行失败"); } catch (Exception e) { e.printStackTrace(); s = Status.error("执行过程发生异常,请检查异常信息"); } return s; } } |
3. 让harness调用中间层
在harness原来的设计中,是让harness直接执行脚本。现在改为让harness去调用中间层(ToastExec),然后中间层(ToastExec)执行脚本,最后将执行结果包装成Status返回给harness。为了达到这个目的,需要更改之前的ToastInterview中的内容。
在配置界面中,当我们选择使用OtherVM on the same computer方式执行脚本的时候,执行的命令是cmd = getOtherVMExecuteCommand();方法的内容如下:
private String getOtherVMExecuteCommand() { char fs = File.separatorChar; char ps = File.pathSeparatorChar;
StringBuffer sb = new StringBuffer(); sb.append("com.sun.javatest.lib.ExecStdTestOtherJVMCmd "); File jvm = qJVM.getValue(); sb.append(jvm == null ? "unknown_jvm" : jvm.getPath()); sb.append(" -classpath $testSuiteRootDir" + fs + "lib" + fs + "jtdemots.jar" + ps + "$testSuiteRootDir" + fs + "lib" + fs + "demoapi.jar" + ps + "$testSuiteRootDir" + fs + "lib" + fs + "javatest.jar "); sb.append("$testExecuteClass $testExecuteArgs"); return sb.toString(); } |
将红色的那两行改成:
sb.append(" -classpath $testSuiteRootDir" + fs + "lib" +fs + "TOAST.jar" + ps
+ "$testSuiteRootDir" + fs + "lib" +fs + "javatest.jar" + ps
+ "$testSuiteRootDir" + fs + "classes ");
sb.append(" com.toast.javatest.script.ToastExec$testExecuteClass $testExecuteArgs");
这样在harness就会将testsuite根目录下的classes目录加进classpath中,并且在执行“java.exe$testExecuteClass $testExecuteArgs”时,就改成了“java.exe com.toast.javatest.script.ToastExec $testExecuteClass$testExecuteArgs”,从直接执行脚本的方式改成了调用中间层执行脚本。
4. 打包执行
将TOAST工程重新打包,放到demoTS\lib下。然后写三个脚本:一个通过,一个失败,一个异常。将java脚本文件拷贝到test目录下,将对应的class连同包路径文件夹拷贝到demoTS\classes下面,。点击run.bat,打开workdir,load配置文件。运行,结果如下所示:
上图失败、通过、异常三份天下的格局证明我们的设计成功了。
5. 更多扩展
用上面这种方式,除了可以执行自定义的java脚本,也可以执行其它任何一种脚本(如C\C++\TXT\python等)。只要有对应的编译执行器就行了。
操作方法就是将中间层(ToastExec)用反射执行java脚本那一段,改成新开一个进程,用第三方的编译执行器执行对应的脚本,然后通过进程的exitCode来判断脚本执行失败还是成功。