如何生成源代码以创建我正在调试的对象?

Dan*_*lan 8 java testing automated-tests code-generation

我的典型场景:

  1. 我工作的遗留代码有一个只有生产中的客户端才有的错误
  2. 我附加一个调试器,并找出如何重现在这个问题上他们的给定系统输入.但是,我不知道为什么错误发生了.
  3. 现在我想在我的本地系统上编写一个自动化测试来尝试重现然后修复bug

最后一步真的很难.输入可能非常复杂,并且有很多数据.手动创建输入(例如:P p = new P(); p.setX("x"); p.setY("x");想象这样做1000次以创建对象)非常繁琐且容易出错.事实上你可能会注意到我刚给出的例子中有一个拼写错误.

是否有一种自动方式从我的调试器中的断点获取字段并生成将创建该对象的源代码,以相同的方式填充?

我唯一想到的就是序列化这个输入(例如使用Xstream).我可以将其保存到文件中并在自动测试中将其读回.这有一个主要问题:如果类以某种方式更改(例如:重命名了字段/ getter/setter名称),我将无法再反序列化该对象.换句话说,测试非常脆弱.

Ale*_*ien 1

众所周知,当对象更改其版本(内容、字段命名)时,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);
  }
}
Run Code Online (Sandbox Code Playgroud)

需要进一步的 getter 和 setter,以及将版本初始化为 CURRENT_VERSION 的构造函数。

如果您更改或添加适当的读写版本,这种序列化可以安全地重构。对于使用外部库中的类而不是您的控件的复杂对象,可能需要更多工作,但字符串、列表很容易序列化。