我的典型场景:
- 我处理的遗留代码有一个只有生产中的客户有的错误
- 我附加了一个调试器,并找出如何在他们的输入的情况下在他们的系统上重现该问题。但是,我不知道为什么会发生错误。
- 现在我想在我的本地系统上编写一个自动化测试来尝试重现然后修复错误
最后一步真的很难。输入可能非常复杂并且包含大量数据。手动创建输入(例如:P p = new P(); p.setX("x"); p.setY("x");
想象这样做 1000 次以创建对象) 非常繁琐且容易出错。事实上,您可能会注意到我刚才给出的示例中有一个拼写错误。
是否有一种自动方法可以从我的调试器中的断点获取一个字段并生成将创建该对象的源代码,并以相同的方式填充?
我唯一想到的就是序列化这个输入(例如使用 Xstream)。我可以将其保存到一个文件中,然后在自动化测试中将其读回。这有一个主要问题:如果类以某些方式更改(例如:重命名字段/getter/setter 名称),我将无法再反序列化该对象。换句话说,测试非常脆弱。
最佳答案
众所周知,Java 标准序列化在对象更改其版本(内容、字段命名)时不是很有用。它非常适合快速演示项目。
更适合您的需求的是 objetcs 支持您自己的(二进制)自定义序列化的方法:
这个不难,用DataOutputStream
写出一个对象的所有字段。但是现在引入 versiong,首先写出一个 versionId
。只有一个版本的对象,写出 versionId 1。这样你就可以稍后,当你必须在你的对象中引入一个变化时,删除字段,添加字段,提高版本号。
这样的 ICustomSerializable
将首先在 readObject() 方法中从输入流中读取版本号,并根据版本 Id 调用 readVersionV1() 或例如 readVersionV2( ).
public Interface ICustomSerializable {
void writeObject(DataOutputStream dos);
Object readObject(DataInputStream dis);
}
public Class Foo {
public static final VERSION_V1 = 1;
public static final VERSION_V2 = 2;
public static final CURRENT_VERSION = VERSION_V2;
private int version;
private int fooNumber;
private double fooDouble;
public void writeObject(DataOutputStream dos) {
dos.writeInt(this.version);
if (version == VERSION_V1) {
writeVersionV1(dos);
} else (version == VERSION_V2) {
writeVersionV2(dos);
} else {
throw new IllegalFormatException("unkown version: " + this.version);
}
}
public void writeVersionV1(DataOutputStream dos) {
writeInt(this.fooNumber);
writeDouble(this.fooValue);
}
}
需要进一步的 getter 和 setter,以及一个将版本初始化为 CURRENT_VERSION 的构造函数。
如果您还更改或添加适当的读写版本,这种序列化对于重构是安全的。对于使用不受您控制的外部库中的类的复杂对象,它可能需要更多工作,但字符串、列表很容易序列化。
关于java - 如何生成源代码来创建我正在调试的对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3251190/