序列性 java_Java项目中所有类的单元测试可序列化性

我的Java项目中有数千个类。 其中一些实现了可序列化的接口。 现在这是一个问题。 可能有人可以上课,添加既不是临时的也不是可序列化的新变量。 代码可以正常编译,但是进程会在运行时崩溃。

为了说明这一点

class Foo implements Serializable {  .... // all good }

class Foo implements Serializable

{

// OOps, executorService is not serializable.  It's not declared as transient either

private ExecutorService executorService = ..

}

我正在考虑编写将通过所有类并确保"真正的可序列化"的单元测试。 我已经阅读了一些有关序列化特定对象的讨论。 我了解该过程,但这需要

1)创建一个对象。

2)序列化然后

3)反序列化。

有没有更有效,更实用的方法。 也许要使用反射。 遍历所有类,如果类具有可序列化的属性,则所有属性必须可序列化或具有transient关键字。

有什么想法吗?

1) creating an object. 2) serializing and then 3) deserializing.

此列表不完整;您还需要初始化。考虑示例:

class CanBeSerialized implements Serializable {

private String a; // serializable

private Thread t; // not serializable

}

class CannotBeSerialized implements Serializable {

private String a;                // serializable

private Thread t = new Thread(); // not serializable

}

您可以序列化和反序列化第一个,但第二个将得到NotSerializableException。更复杂的是,如果使用接口,您将永远无法判断类是否将通过序列化,因为将流传输的是该接口背后的类的具体对象:

class PerhapsCanBeSerializedButYouNeverKnow implements Serializable {

private Runnable r; // interface type - who knows?

}

前提是您可以保证所有类和要测试的类所使用的类都满足以下条件:

默认构造函数存在,

字段中没有接口类型,

那么您可以通过反射自动创建和初始化它们,然后测试序列化。但这是一个非常困难的条件,不是吗?否则,正确的初始化将取决于手动工作。

您可以通过其他方式使用反射:遍历要检查的Class对象的列表,获取它们的Field[],并验证它们是否是瞬时的(Field.getModifiers())或它们是否实现了Serializable直接(Field.getType().getInterfaces())或间接(通过超级接口或类)。另外,请考虑要检查的深度,具体取决于序列化机制的工作深度。

正如Ryan正确指出的那样,如果代码足够邪恶,则此静态序列化检查将失败:

class SeeminglySerializable implements Serializable {

// ...

private void writeObject/readObject() {

throw new NotSerializableException();

}

}

或readObject()/writeObject()实施不当。要针对此类问题进行测试,您需要实际测试序列化过程,而不是其背后的代码。

您仍然没有考虑神奇的readObject和writeObject方法。如果这些被使用,则您列出的任何规则都将不适用。

@RyanStewart我想提一下,我的算法只是一个近似值,但是它让我感到困惑。谢谢!

如果序列化是应用程序的关键部分,请在测试中包括序列化。就像是:

@Test

public void aFooSerializesAndDeserializesCorrectly {

Foo fooBeforeSerialization = new Foo();

ReflectionUtils.randomlyPopulateFields(foo);

Foo fooAfterSerialization = Serializer.serializeAndDeserialize(foo);

assertThat(fooAfterSerialization, hasSameFieldValues(fooBeforeSerialization));

}

编辑:randomlyPopulateFields的简单实现:

public static void randomlyPopulateFields(final Object o) {

ReflectionUtils.doWithFields(o.getClass(), new ReflectionUtils.FieldCallback() {

public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {

ReflectionUtils.makeAccessible(field);

ReflectionUtils.setField(field, o, randomValueFor(field.getType()));

}

private Random r = new Random();

private Object randomValueFor(Class< ? > type) {

if (type == String.class) {

return String.valueOf(r.nextDouble());

} else if (type == Boolean.class || type == Boolean.TYPE) {

return r.nextBoolean();

} else if (type == Byte.class || type == Byte.TYPE) {

return (byte) r.nextInt();

} else if (type == Short.class || type == Short.TYPE) {

return (short) r.nextInt();

} else if (type == Integer.class || type == Integer.TYPE) {

return r.nextInt();

} else if (type == Long.class || type == Long.TYPE) {

return (long) r.nextInt();

} else if (Number.class.isAssignableFrom(type) || type.isPrimitive()) {

return Byte.valueOf("1234");

} else if (Date.class.isAssignableFrom(type)) {

return new Date(r.nextLong());

} else {

System.out.println("Sorry, I don't know how to generate values of type" + type);

return null;

}

}

});

}

您指的是什么ReflectionUtils?

没有特别的限制。我想我已经在某个地方的某个库中看到了这样的实用程序,但是我通常只是编写自己的。任何创建适当填充的对象的方法都可以使用。关键是,如果您要测试序列化,则需要序列化对象。

问题是,如果不提供有关如何初始化对象的元数据,就无法轻松实现这种方法。这就是为什么我发现您的答案具有误导性的原因,因为它欺骗了看似容易解决的问题。

添加了一个简单的实现。最糟糕的部分是必须分别处理所有数字类型。它不是很难。这也是获取填充对象进行测试的唯一可能方法。实际方法取决于您已经建立了什么样的测试基础架构。

大。现在,您清楚地显示出方法背后没有任何魔力,只有努力。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值