我有一个后端系统,我们使用第三方Java API从我们自己的应用程序访问.我可以像普通用户一样以其他用户的身份访问系统,但我没有虔诚的权力.
因此,为了简化测试,我想运行一个真实的会话并记录API调用,并保留它们(最好是可编辑的代码),这样我们以后可以通过API调用进行干测试运行,只需从记录会话中返回相应的响应 - 这是重要的部分 - 无需与上述后端系统对话.
因此,如果我的应用程序包含表单上的行:
Object b = callBackend(a);
Run Code Online (Sandbox Code Playgroud)
我希望框架首先捕获callBackend()返回的b给定参数a,然后当我在任何以后执行干运行时说"嘿,给定此调用应该返回b".a和b的值将相同(如果不是,我们将重新运行录制步骤).
我可以覆盖提供API的类,因此所有捕获的方法调用都将通过我的代码(即不需要字节代码检测来改变我控制之外的类的行为).
我应该研究什么框架才能做到这一点?
编辑:请注意,赏金猎人应提供实际代码,以证明我寻找的行为.
实际上,您可以使用代理模式构建此类框架或模板.在这里我解释一下,如何使用动态代理模式来完成它.这个想法是,
hashCode与equals从有效的查找该包装类的方法,Map如数据结构.录音机如何工作:
如何重播工作:
现在,让我们看一下实现.如果您的API MyApi如下:
public interface MyApi {
public String getMySpouse(String myName);
public int getMyAge(String myName);
...
}
Run Code Online (Sandbox Code Playgroud)
现在我们将记录并重放调用public String getMySpouse(String myName).为此,我们可以使用类来存储调用信息,如下:
public class RecordedInformation {
private String methodName;
private Object[] args;
private Object returnValue;
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public Object[] getArgs() {
return args;
}
public void setArgs(Object[] args) {
this.args = args;
}
public Object getReturnValue() {
return returnType;
}
public void setReturnValue(Object returnValue) {
this.returnValue = returnValue;
}
@Override
public int hashCode() {
return super.hashCode(); //change your implementation as you like!
}
@Override
public boolean equals(Object obj) {
return super.equals(obj); //change your implementation as you like!
}
}
Run Code Online (Sandbox Code Playgroud)
现在主要部分是The RecordReplyManager.这RecordReplyManager为您提供了API的代理对象,具体取决于您是否需要录制或重播.
public class RecordReplyManager implements java.lang.reflect.InvocationHandler {
private Object objOfApi;
private boolean isForRecording;
public static Object newInstance(Object obj, boolean isForRecording) {
return java.lang.reflect.Proxy.newProxyInstance(
obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(),
new RecordReplyManager(obj, isForRecording));
}
private RecordReplyManager(Object obj, boolean isForRecording) {
this.objOfApi = obj;
this.isForRecording = isForRecording;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result;
if (isForRecording) {
try {
System.out.println("recording...");
System.out.println("method name: " + method.getName());
System.out.print("method arguments:");
for (Object arg : args) {
System.out.print(" " + arg);
}
System.out.println();
result = method.invoke(objOfApi, args);
System.out.println("result: " + result);
RecordedInformation recordedInformation = new RecordedInformation();
recordedInformation.setMethodName(method.getName());
recordedInformation.setArgs(args);
recordedInformation.setReturnValue(result);
//persist your information
} catch (InvocationTargetException e) {
throw e.getTargetException();
} catch (Exception e) {
throw new RuntimeException("unexpected invocation exception: " +
e.getMessage());
} finally {
// do nothing
}
return result;
} else {
try {
System.out.println("replying...");
System.out.println("method name: " + method.getName());
System.out.print("method arguments:");
for (Object arg : args) {
System.out.print(" " + arg);
}
RecordedInformation recordedInformation = new RecordedInformation();
recordedInformation.setMethodName(method.getName());
recordedInformation.setArgs(args);
//if your invocation information (this RecordedInformation) is found in the previously collected map, then return the returnValue from that RecordedInformation.
//if corresponding RecordedInformation does not exists then invoke the real method (like in recording step) and wrap the collected information into RecordedInformation and persist it as you like!
} catch (InvocationTargetException e) {
throw e.getTargetException();
} catch (Exception e) {
throw new RuntimeException("unexpected invocation exception: " +
e.getMessage());
} finally {
// do nothing
}
return result;
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果你想记录方法调用,你只需要获得一个像下面这样的API代理:
MyApi realApi = new RealApi(); // using new or whatever way get your service implementation (API implementation)
MyApi myApiWithRecorder = (MyApi) RecordReplyManager.newInstance(realApi, true); // true for recording
myApiWithRecorder.getMySpouse("richard"); // to record getMySpouse
myApiWithRecorder.getMyAge("parker"); // to record getMyAge
...
Run Code Online (Sandbox Code Playgroud)
并重播你需要的一切:
MyApi realApi = new RealApi(); // using new or whatever way get your service implementation (API implementation)
MyApi myApiWithReplayer = (MyApi) RecordReplyManager.newInstance(realApi, false); // false for replaying
myApiWithReplayer.getMySpouse("richard"); // to replay getMySpouse
myApiWithRecorder.getMyAge("parker"); // to replay getMyAge
...
Run Code Online (Sandbox Code Playgroud)
你完成了!
编辑: 录音机和重播器的基本步骤可以用上面提到的方式完成.现在它取决于您,您希望如何使用或执行这些步骤.您可以在录音机和重放代码块中随心所欲地执行任何操作,只需选择您的实现!
| 归档时间: |
|
| 查看次数: |
3965 次 |
| 最近记录: |