問題描述
我的典型場景:
- 我處理的遺留代碼有一個只有生產中的客戶端才有的錯誤
- 我附加了一個調試器,并找出如何在 他們的 系統上重現該問題給 他們的 輸入.但是,我還不知道為什么會發生錯誤.
- 現在我想在我的本地系統上編寫一個自動化測試來嘗試重現然后修復錯誤
- The legacy code I work on has a bug that only a client in production is having
- I attach a debugger and figure out how to reproduce the issue on their system given their input. But, I don't know why the error is happening yet.
- Now I want to write an automated test on my local system to try and reproduce then fix the bug
最后一步真的很難.輸入可能非常復雜,并且包含大量數據.手動創建輸入(例如:P p = new P(); p.setX("x"); p.setY("x");
想象這樣做 1000 次來創建對象) 非常繁瑣且容易出錯.事實上,您可能會注意到我剛才給出的示例中有一個錯字.
That last step is really hard. The input can be very complex and have a lot of data to it. Creating the input by hand (eg: P p = new P(); p.setX("x"); p.setY("x");
imagine doing this 1000 times to create the object) is very tedious and error prone. In fact you may notice there's a typo in the example I just gave.
是否有一種自動化的方法可以從我的調試器中的斷點獲取字段并生成將創建該對象的源代碼,并以相同的方式填充?
我想出的唯一方法就是序列化這個輸入(例如,使用 Xstream).我可以將其保存到文件中并在自動化測試中將其讀回.這有一個主要問題:如果類以某些方式更改(例如:重命名字段/getter/setter 名稱),我將無法再反序列化對象.換句話說,測試非常脆弱.
The only thing I've come up with is to serialize this input (using Xstream, for example). I can save that to a file and read it back in in an automated test. This has a major problem: If the class changes in certain ways (eg: a field/getter/setter name is renamed), I won't be able to deserialize the object anymore. In other words, the tests are extremely fragile.
推薦答案
眾所周知,Java 標準序列化在對象更改其版本(內容、字段命名)時不是很有用.它適用于快速演示項目.
Java standard serialisation is well know to be not very usefull when objects change their version ( content, naming of fields). Its fine for quick demo projects.
更適合您的需求,是 objetcs 支持您自己的(二進制)自定義序列化的方法:
這并不難,使用 DataOutputStream
寫出一個對象的所有字段.但是現在引入versiong,首先寫出一個versionId
.只有一個版本的對象,寫出 versionId 1.這樣以后,當您必須在對象中引入更改時,刪除字段、添加字段、提高版本號.
More suitable for your needs, is the approach that objetcs support your own (binary) custom serialisation:
This is not difficult, use DataOutputStream
to write out all fields of an object. But now introduce versiong, by first writing out a versionId
. Objects that have only one version, write out versionId 1. That way you can later, when you have to introduce a change in your objetcs, remove fields, add fields, raise the version number.
這樣的 ICustomSerializable
將首先在 readObject() 方法中從輸入流中讀取版本號,并根據版本 ID 調用 readVersionV1() 或例如 readVersionV2().
Such a ICustomSerializable
will then first read out the version number from the input stream, in a readObject() method, and depending on the version Id call readVersionV1() or e.g 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 的構造函數.
Further getter and setter, and a constructor with initialised the version to CURRENT_VERSION is needed.
如果您更改或添加適當的讀寫版本,這種序列化是安全的重構.對于使用不受您控制的外部庫中的類的復雜對象,它可以做更多的工作,但字符串、列表很容易序列化.
This kind of serialisazion is safe to refactoring if you change or add also the appropriate read and write version. For complex objects using classes from external libs not und your controll, it can be more work, but strings, lists are easily serialized.
這篇關于如何生成源代碼來創建我正在調試的對象?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!