Doge log

Abby CTO 雑賀 力王のオフィシャルサイトです

TestCaseその2

  • Eclipseからも起動したい。
  • 既存のTestRunnerを使えないと辛い。(ant、maven

というニーズに妄想で対応。
以下危険コード。

RhinoTestCase

package test;

import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

import org.mozilla.javascript.Context;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.Script;
import org.mozilla.javascript.ScriptableObject;

public class RhinoTestCase extends TestCase {

	private ScriptableObject scope;

	public RhinoTestCase() {

	}

	public RhinoTestCase(String testName, ScriptableObject scope) {
		super(testName);
		this.setName(testName);
		this.scope = scope;
	}

	public void testScript() {

	}

	protected Context enter() {
		Context cx = Context.enter();
		cx.setWrapFactory(new TestWrapFactory());
		return cx;
	}

	public Test createJsTestCase() throws Throwable {

		String path = this.getClass().getName();
		path = path.replace('.', '/') + ".js";
		ClassLoader loader = Thread.currentThread().getContextClassLoader();
		InputStream in = null;
		Reader reader = null;
		TestSuite suite = new TestSuite(path);
		try {
			in = loader.getResourceAsStream(path);
			reader = new InputStreamReader(in, "UTF-8");
			Context cx = enter();
			ScriptableObject scope = cx.initStandardObjects();
			
			String assert = "var assert = Packages.junit.framework.Assert; for(var v in assert){ this[v] = assert[v];}";
			cx.evaluateString(scope, assert, "assert", 0, null);
			Script script = cx.compileReader(reader, new File(path).getName(),
					0, null);
			Object result = script.exec(cx, scope);
			Object[] list = scope.getIds();
			cx.exit();
			for (int i = 0; i < list.length; i++) {
				String name = list[i].toString();
				if (name.toString().startsWith("test")) {
					Object o = scope.get(name, null);
					Function f = (Function) o;
					RhinoTestCase test = new RhinoTestCase(name, scope);
					suite.addTest(test);
				}
			}
			return suite;
		} finally {
			if (in != null) {
				in.close();
			}
		}
	}

	protected void runTest() throws Throwable {
		Context cx = Context.enter();
		Object o = scope.get(this.getName(), null);
		Function func = (Function) o;
		func.call(cx, scope, scope, null);
		cx.exit();
	}

}

以下は使う側の人のコード

FooTest.js

function testFunction2(){
		java.lang.System.out.println('TEST1');
		assertEquals(true, true);
		//assertEquals(true, true);
}

function testFunction1(){
		java.lang.System.out.println('TEST2');
		assertEquals(true, true);
		//assertEquals(true, true);
}

JsUnitコンパチのテストケースが動きます。

FooTest.java

package test;

import junit.framework.Test;

public class FooTest extends RhinoTestCase {

	public static Test suite() throws Throwable {
		return new FooTest().createJsTestCase();
	}
}

起動用テストケースはこんだけ。
jsをどうやって読み込ませるか、そこのルールだけかなと。
これ以上は少なくできなくない?
ファイルパス指定がうざいのでJUnitのテストケースと同名で取得する。
つーかjsである以上java(Eclipseなど)から呼ぶにはワンクッション入るので仕方ないかなと。
流れ

  • JUnitの名前でjsファイル取得
  • コンパイル
  • Functionを抜きだす
  • TestCaseに入れる
  • TestSuiteとしてまとめる
  • 実行

あとはテスト対象であるライブラリを読み込むためのloadメソッドを実装する必要がある。
FunctionObjectはMethodラッパーチックだけどラップしないでそのまま書いてしまいたい。
FunctionObject周りは情報少ないのできっついなあ。
できなければ

  • javaのクラスで実装
  • jsでeval
  • scope共有であたかもビルトインに!

のパターンでうごくっちゃあ動く。汚いけどね。

うくく。