片山です。こんにちは。
とりあえずテストインターフェース生成を作ってみました。
Targetクラスが、テスト対象クラスになります。
TestInterfaceGeneratorにソース出力パスとテストインターフェースを
作りたいclass(この場合だとTarget.class)を渡すと、メソッドとフィールドを見て
同名のインターフェースを生成します。
実際のテスト時は、TestInvokeクラスに書いてあるように、実インスタンスと
Proxyインスタンスを生成します。この手順はみやむこさんの方法と同一です。
Target target = new Target();
TargetTestInterface testInterface =
(TargetTestInterface)PrivateProxy.
createProxy(target,TargetTestInterface.class);
テスト時のメソッドに関しては、みやむこさんのPrivateProxyと呼び出し方は同一です。
フィールドに関してはテストインターフェース生成時に
「setフィールド名+_TestInvoke」と「getフィールド名+_TestInvoke」と
いうメソッドを生成しますので、それを使って呼び出しを行います。
例えば、privateFieldというメンバ変数に対してはsetPrivateField_TestInvocation
というメソッドが定義されるので、これを使って
testInterface.setPrivateField_TestInvocation(5);
とテスト時にセットします。
PrivateProxy内部で「_TestInvoke」と「set,get」をキーにしてメソッドを調べ、
もし合致していればフィールドに対して直接アクセスを行います。
TestInterfaceGeneratorはとりあえず実装ですが、Antタスクに入れたりすれば
自動化は容易と思います。
---Target
package testinterface;
import java.io.IOException;
public class Target{
protected String protectedField = "protected";
private int privateField = 100;
private int calc(int num){
return num*2;
}
protected String append(String name1,String name2){
return name1+ protectedField + name2;
}
private void exception() throws IOException,IllegalArgumentException{
}
}
---TestInterfaceGenerator
package testinterface;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class TestInterfaceGenerator{
public void generate(String generateDir,Class targetClass)
throws IOException{
String packageName = targetClass.getPackage().getName()+".test";
String targetClassName =
GeneratorUtils.getClassName(targetClass.getName());
String interfaceName = targetClassName+"TestInterface";
String dirPath = generateDir + "/" + packageName.replace('.','/');
File javaFileDir = new File(dirPath);
if(!javaFileDir.exists())
javaFileDir.mkdirs();
String javaFilePath = dirPath+"/"+interfaceName;
File javaFile = new File(javaFilePath+".java");
if(!javaFile.exists())
javaFile.createNewFile();
PrintWriter writer = new PrintWriter(new FileOutputStream(javaFile));
writer.println("package " + packageName + ";");
writer.println("public interface " + interfaceName);
writer.println("{");
Field[] fields = targetClass.getDeclaredFields();
for(int i = 0;i < fields.length;i++){
Field field = fields[i];
String fieldName = field.getName();
String methodName = GeneratorUtils.startCharToUpperCase(fieldName);
Class type = field.getType();
writer.println("\t"+"void set" + methodName
+ GeneratorConst.FIELDINVOKE_IDENTIFIRE+"(" + type.getName() + " "
+ fieldName + ");");
writer.println("\t"+type.getName() + " get" + methodName
+ GeneratorConst.FIELDINVOKE_IDENTIFIRE+"();");
}
Method[] methods = targetClass.getDeclaredMethods();
for(int i = 0;i < methods.length;i++){
Method method = methods[i];
String methodName = method.getName();
Class returnType = method.getReturnType();
Class[] paramTypes = method.getParameterTypes();
Class[] exceptionTypes = method.getExceptionTypes();
writer.print("\t"+returnType.getName() + " " + methodName + "(");
for(int j = 0;j < paramTypes.length;j++){
if(j != 0)
writer.print(",");
writer.print(paramTypes[j].getName() + " param" + j);
}
writer.print(")");
for(int j = 0;j < exceptionTypes.length;j++){
if(j == 0)
writer.print(" throws ");
else
writer.print(",");
writer.print(exceptionTypes[j].getName());
}
writer.println(";");
}
writer.println();
writer.println("}");
writer.flush();
writer.close();
}
}
----PrivateProxy
package testinterface;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public final class PrivateProxy{
public static Object createProxy(final Object target, Class interfaceClass){
InvocationHandler handler = new InvocationHandler(){
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable{
if(method.getName().endsWith(
GeneratorConst.FIELDINVOKE_IDENTIFIRE)){
String methodName = method.getName();
boolean set = methodName.startsWith("set");
String fieldName =
methodName.substring(3,methodName.lastIndexOf(
GeneratorConst.FIELDINVOKE_IDENTIFIRE));
fieldName = GeneratorUtils.startCharToLowerCase(fieldName);
Field targetField =
target.getClass().getDeclaredField(fieldName);
targetField.setAccessible(true);
if(set){
targetField.set(target,args[0]);
return null;
}
else{
return targetField.get(target);
}
}
else{
Method targetMethod =
target.getClass()
.getDeclaredMethod(method.getName(),
method.getParameterTypes());
targetMethod.setAccessible(true);
return targetMethod.invoke(target,args);
}
}
};
return Proxy.newProxyInstance(
interfaceClass.getClassLoader(),
new Class[] { interfaceClass },handler);
}
}
--GeneratorConst
package testinterface;
public interface GeneratorConst{
public static final String FIELDINVOKE_IDENTIFIRE = "_TestInvocation";
}
--GeneratorUtils
package testinterface;
public class GeneratorUtils{
public static String startCharToUpperCase(String text){
return text.substring(0,1).toUpperCase()
+ text.substring(1,text.length());
}
public static String startCharToLowerCase(String text){
return text.substring(0,1).toLowerCase()
+ text.substring(1,text.length());
}
public static String getClassName(String fqdn){
return fqdn.substring(fqdn.lastIndexOf(".")+1,fqdn.length());
}
}
----InvokeTest
package testinterface;
import testinterface.test.TargetTestInterface;
public class InvokeTest{
public static void main(String[] args)
{
Target target = new Target();
TargetTestInterface testInterface =
(TargetTestInterface)PrivateProxy
.createProxy(target,TargetTestInterface.class);
System.out.println(testInterface.append("aa","bb"));
System.out.println(testInterface.calc(10));
testInterface.setPrivateField_TestInvocation(5);
System.out.println(testInterface.getPrivateField_TestInvocation());
}
}
-------------------------------------------
株式会社キャピタル・アセット・プランニング
システム開発部
片山 暁雄
mail:katayama@....jp
Tel:03-3256-1570
Fax:03-5296-9911
-------------------------------------------