我的典型场景:
- 我处理的遗留代码有一个错误,只有生产中的客户端才会遇到
- 我附加了一个调试器并找出如何重现该问题their系统给定their输入。但是,我还不知道为什么会发生错误。
- 现在我想在本地系统上编写一个自动化测试来尝试重现然后修复错误
最后一步真的很难。输入可能非常复杂并且包含大量数据。手动创建输入(例如:P p = new P(); p.setX("x"); p.setY("x");
想象一下这样做 1000 次来创建对象)是非常乏味且容易出错的。事实上,您可能会注意到我刚刚给出的示例中有一个拼写错误。
是否有一种自动方法可以从调试器中的断点获取字段并生成创建该对象的源代码,并以相同的方式填充?
我唯一想到的就是序列化这个输入(例如使用 Xstream)。我可以将其保存到文件中并在自动化测试中将其读回。这有一个主要问题:如果类以某些方式发生更改(例如:重命名字段/getter/setter 名称),我将无法再反序列化该对象。换句话说,测试极其脆弱。
众所周知,当对象更改其版本(内容、字段命名)时,Java 标准序列化并不是很有用。它非常适合快速演示项目。
更适合您的需求的是对象支持您自己的(二进制)自定义序列化的方法:
这个并不难,用DataOutputStream
写出对象的所有字段。但现在引入 versiong,首先写出一个versionId
。对于只有一个版本的对象,写出 versionId 1。这样,当您必须在对象中引入更改时,您可以删除字段、添加字段、提高版本号。
Such a 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 的构造函数。
如果您更改或添加适当的读写版本,这种序列化可以安全地重构。对于使用外部库中的类而不是您的控件的复杂对象,可能需要更多工作,但字符串、列表很容易序列化。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)