TestCaseその2
というニーズに妄想で対応。
以下危険コード。
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など)から呼ぶにはワンクッション入るので仕方ないかなと。
流れ
あとはテスト対象であるライブラリを読み込むためのloadメソッドを実装する必要がある。
FunctionObjectはMethodラッパーチックだけどラップしないでそのまま書いてしまいたい。
FunctionObject周りは情報少ないのできっついなあ。
できなければ
- javaのクラスで実装
- jsでeval
- scope共有であたかもビルトインに!
のパターンでうごくっちゃあ動く。汚いけどね。
うくく。