模拟 class 实例会影响静态实例初始化
Mocking a class instance affects the static instance initialization
我 运行 遇到一个问题,如果我模拟一个 class 实例,那么同一个 class 中的静态实例不会正确初始化。
我有一个与问题行相关的第三方代码的真实示例:
...
public class Schema implements SchemaProvider
{
public static final Schema instance = new Schema();
private volatile Keyspaces distributedKeyspaces = Keyspaces.none();
private final Keyspaces localKeyspaces;
private final boolean online;
...
private Schema()
{
this.online = isDaemonInitialized();
this.localKeyspaces = (FORCE_LOAD_LOCAL_KEYSPACES || isDaemonInitialized() || isToolInitialized())
? Keyspaces.of(SchemaKeyspace.metadata(), SystemKeyspace.metadata())
: Keyspaces.none();
}
@VisibleForTesting
public Schema(boolean online, Keyspaces localKeyspaces)
{
this.online = online;
this.localKeyspaces = localKeyspaces;
}
...
然后在另一个项目中使用项目 jar,其中 Schema
在测试中被模拟:
Schema schema = Mockito.mock(Schema.class);
根据我的理解,这应该不会影响静态实例初始化,即 Schema.instance
。但是,我 运行 遇到一个问题,即静态实例未正确初始化且其属性为 null
,即:
assert Schema.instance.distributedKeyspaces == null;
assert Schema.instance.localKeyspaces == null;
我发现我可以通过创建虚拟实例来解决测试项目中的初始化问题:
new Schema(false, Keyspaces.none());
Schema schema = Mockito.mock(Schema.class);
// which gives me:
assert Schema.instance.distributedKeyspaces != null;
assert Schema.instance.localKeyspaces != null;
我未能找到有关此用例的任何信息。所以我很想听听对这种行为的解释,如果它是预期的或一些不常见的用法,运行s 是一种未定义的行为。有没有更好的方法来解决这个问题? (最好不改第三方库)
Java版本:openjdk版本“11.0.12”2021-07-20
Mockito 版本:3.5.0
似乎 Schema.class
加载了 class Schema
但没有初始化它。所以当调用Mockito.mock
创建代理对象时,class被初始化,但是为static finalinstance
构造Schema
由于某些原因没有正确完成。我有经验证据,但没有参考文档或代码。我在 Mockito issue tracker
中询问
所以解决方案是确保在调用 Mockito 之前加载并初始化 class。例如,通过调用 Class.forName
:
Class.forName(Schema.class.getName());
// and then mock
Schema schema = Mockito.mock(Schema.class);
或
Schema schema = Mockito.mock((Class<Schema>)Class.forName(Schema.class.getName()));
我 运行 遇到一个问题,如果我模拟一个 class 实例,那么同一个 class 中的静态实例不会正确初始化。
我有一个与问题行相关的第三方代码的真实示例:
...
public class Schema implements SchemaProvider
{
public static final Schema instance = new Schema();
private volatile Keyspaces distributedKeyspaces = Keyspaces.none();
private final Keyspaces localKeyspaces;
private final boolean online;
...
private Schema()
{
this.online = isDaemonInitialized();
this.localKeyspaces = (FORCE_LOAD_LOCAL_KEYSPACES || isDaemonInitialized() || isToolInitialized())
? Keyspaces.of(SchemaKeyspace.metadata(), SystemKeyspace.metadata())
: Keyspaces.none();
}
@VisibleForTesting
public Schema(boolean online, Keyspaces localKeyspaces)
{
this.online = online;
this.localKeyspaces = localKeyspaces;
}
...
然后在另一个项目中使用项目 jar,其中 Schema
在测试中被模拟:
Schema schema = Mockito.mock(Schema.class);
根据我的理解,这应该不会影响静态实例初始化,即 Schema.instance
。但是,我 运行 遇到一个问题,即静态实例未正确初始化且其属性为 null
,即:
assert Schema.instance.distributedKeyspaces == null;
assert Schema.instance.localKeyspaces == null;
我发现我可以通过创建虚拟实例来解决测试项目中的初始化问题:
new Schema(false, Keyspaces.none());
Schema schema = Mockito.mock(Schema.class);
// which gives me:
assert Schema.instance.distributedKeyspaces != null;
assert Schema.instance.localKeyspaces != null;
我未能找到有关此用例的任何信息。所以我很想听听对这种行为的解释,如果它是预期的或一些不常见的用法,运行s 是一种未定义的行为。有没有更好的方法来解决这个问题? (最好不改第三方库)
Java版本:openjdk版本“11.0.12”2021-07-20
Mockito 版本:3.5.0
似乎 Schema.class
加载了 class Schema
但没有初始化它。所以当调用Mockito.mock
创建代理对象时,class被初始化,但是为static finalinstance
构造Schema
由于某些原因没有正确完成。我有经验证据,但没有参考文档或代码。我在 Mockito issue tracker
所以解决方案是确保在调用 Mockito 之前加载并初始化 class。例如,通过调用 Class.forName
:
Class.forName(Schema.class.getName());
// and then mock
Schema schema = Mockito.mock(Schema.class);
或
Schema schema = Mockito.mock((Class<Schema>)Class.forName(Schema.class.getName()));