[英]How can I access private class members in Java?
I have data model classes that contain private fields which are meant to be read-only (via a getter function). 我有数据模型类,包含私有字段,这些字段是只读的(通过getter函数)。 These fields are set by my JPA persistence provider (eclipselink) during normal operation, using the contents of the database.
这些字段由我的JPA持久性提供程序(eclipselink)在正常操作期间使用数据库的内容设置。 For unit tests, I want to set them to fake values from a mockup of the persistence layer.
对于单元测试,我想将它们设置为来自持久层的模型的伪值。 How can I do that?
我怎样才能做到这一点? How does eclipselink set these values, anyway?
无论如何,eclipselink如何设置这些值?
Simplified example: 简化示例:
@Entity
class MyEntity
{
@Id
private Integer _ix;
public Integer ixGet()
{
return this._ix;
}
}
Can you just Mock the Entity itself, providing your own implemenations of the getters? 你可以嘲笑实体本身,提供你自己的getter实现吗?
You could create an anonymous extension in your mock persistence layer: 您可以在模拟持久层中创建匿名扩展:
MyEntity x = new MyEntity() {
public Integer ixGet() { return new Integer(88); }
};
You need to use the Reflection API. 您需要使用Reflection API。 Use Class.getField() to get the field, then call setAccessable(true) on that field so that you may write to it, even though it is private, and finally you may call set() on it to write a new value.
使用Class.getField()来获取该字段,然后在该字段上调用setAccessable(true),以便您可以写入它,即使它是私有的,最后您可以在其上调用set()来写入新值。
For example: 例如:
public class A {
private int i;
}
You want to set the field 'i' to 3, even though it is private: 您希望将字段“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);
}
There are a number of exceptions that you will need to handle. 您需要处理许多例外情况。
You can use a test library like Mockito to access objects internal state in read and write mode. 您可以使用像Mockito这样的测试库来以读写模式访问对象内部状态。 For example with Mockito use:
例如,使用Mockito:
//read
Integer i = Whitebox.getInternalState(myEntity,"_ix")
//Write
Whitebox.setInternalState(myEntity,"_ix", 123)
You can use a mocking framework like powermock to by pass encapsulation. 你可以通过封装来使用像powermock这样的模拟框架。 In powermock you'd use
Whitebox.setInternalState(..)
to set a private member. 在powermock中,您将使用
Whitebox.setInternalState(..)
来设置私有成员。
A less invasive method would be to mock the getter method. 一种侵入性较小的方法是模拟getter方法。 Whether this is feasible would depend on what else depends on the internal state but if it is enough, it's the cleaner solution.
这是否可行将取决于其他什么取决于内部状态,但如果它足够,它是更清洁的解决方案。
Some methods I've used in the past: 我过去使用的一些方法:
Another option, if you really hate to make things public, is to create a subclass for testing, and provide public access there. 另一种选择,如果你真的讨厌公开,就是创建一个用于测试的子类,并在那里提供公共访问。
You have a few options: 你有几个选择:
For a bunch of useful techniques, have a look at Michael Feather's book, Working Effectively With Legacy Code 有关一系列有用的技巧,请查看Michael Feather的书“有效地使用遗留代码”
You can add constructor with parameter for your read-only variable. 您可以为只读变量添加带参数的构造函数。 Don't forget to add a default (zero parameter) constructor.
不要忘记添加默认(零参数)构造函数。
@Entity
class MyEntity
{
@Id
private Integer _ix;
public MyEntity(Integer ix) {
_ix = ix;
}
public MyEntity() {
/*
* Default constructor
*/
}
public Integer ixGet()
{
return this._ix;
}
}
The constructor is a best way I think. 构造函数是我认为最好的方法。 If this entity has to be really readonly (not allowed to create new instances in production code at all) you can make constructor with package access and use it only within the tests.
如果此实体必须非常只读(根本不允许在生产代码中创建新实例),则可以使用包访问权限构建器,并仅在测试中使用它。 And there is a possibility that even if you make your default constructor private or with package access, your persistance provider still be able to work with such entity, but not sure though - check with eclipselink docs.
并且即使您将默认构造函数设为私有或具有包访问权限,您的持久性提供程序仍然可以使用此类实体,但不确定 - 请查看eclipselink文档。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.