我的数据模型类包含私有字段,这些字段是只读的(通过getter函数)。这些字段由我的JPA持久性提供程序(eclipselink)在正常操作期间使用数据库的内容设置。对于单元测试,我想将它们设置为来自持久层的模型的伪值。我怎样才能做到这一点?无论如何,eclipselink如何设置这些值?
简化示例:
@Entity
class MyEntity
{
@Id
private Integer _ix;
public Integer ixGet()
{
return this._ix;
}
}
答案 0 :(得分:8)
你能嘲笑实体本身,提供你自己的getter实现吗?
您可以在模拟持久层中创建匿名扩展名:
MyEntity x = new MyEntity() {
public Integer ixGet() { return new Integer(88); }
};
答案 1 :(得分:8)
您需要使用Reflection API。使用Class.getField()来获取该字段,然后在该字段上调用setAccessable(true),以便您可以写入它,即使它是私有的,最后您可以在其上调用set()来写入新值。
例如:
public class A {
private int i;
}
您希望将字段“i”设置为3,即使它是私有的:
void forceSetInt(Object o, String fieldName, int value) {
Class<?> clazz = o.getClass();
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(o, value);
}
您需要处理许多例外情况。
答案 2 :(得分:4)
您可以使用像Mockito这样的测试库来以读写模式访问对象内部状态。例如,使用Mockito:
//read
Integer i = Whitebox.getInternalState(myEntity,"_ix")
//Write
Whitebox.setInternalState(myEntity,"_ix", 123)
答案 3 :(得分:3)
您可以通过封装来使用像powermock这样的模拟框架。在powermock中,您可以使用Whitebox.setInternalState(..)
设置私有成员。
一种侵入性较小的方法是模拟getter方法。这是否可行将取决于其他什么取决于内部状态,但如果它足够,它是更清洁的解决方案。
答案 4 :(得分:2)
我过去使用的一些方法:
答案 5 :(得分:2)
另一个选择,如果你真的讨厌公开,就是创建一个用于测试的子类,并在那里提供公共访问。
您有几个选择:
对于一堆有用的技巧,请看一下Michael Feather的书,Working Effectively With Legacy Code
答案 6 :(得分:2)
您可以为只读变量添加带参数的构造函数。不要忘记添加默认(零参数)构造函数。
@Entity
class MyEntity
{
@Id
private Integer _ix;
public MyEntity(Integer ix) {
_ix = ix;
}
public MyEntity() {
/*
* Default constructor
*/
}
public Integer ixGet()
{
return this._ix;
}
}
答案 7 :(得分:1)
构造函数是我认为最好的方法。如果此实体必须非常只读(根本不允许在生产代码中创建新实例),则可以使用包访问权限构建器,并仅在测试中使用它。即使您将默认构造函数设为私有或具有包访问权限,您的持久性提供程序仍然可以使用此类实体,但不确定 - 请查看eclipselink文档。