如何在 Java 中访问私有类成员?
我有包含私有字段的数据模型类,这些字段是只读的(通过 getter 函数)。 这些字段是由我的 JPA 持久性提供程序 (eclipselink) 在正常操作期间使用数据库的内容设置的。 对于单元测试,我想将它们设置为来自持久层模型的假值。 我怎样才能做到这一点? eclipselink 是如何设置这些值的呢?
简化示例:
@Entity
class MyEntity
{
@Id
private Integer _ix;
public Integer ixGet()
{
return this._ix;
}
}
I have data model classes that contain private fields which are meant to be read-only (via a getter function). These fields are set by my JPA persistence provider (eclipselink) during normal operation, using the contents of the database. 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?
Simplified example:
@Entity
class MyEntity
{
@Id
private Integer _ix;
public Integer ixGet()
{
return this._ix;
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
我过去使用过的一些方法:
Some methods I've used in the past:
如果您真的不想公开,另一种选择是创建一个子类进行测试,并在那里提供公共访问。
您有几个选择:
对于一堆有用的技术,请查看 Michael Feather 的书,有效地使用旧代码
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
您可以为只读变量添加带参数的构造函数。 不要忘记添加默认(零参数)构造函数。
You can add constructor with parameter for your read-only variable. Don't forget to add a default (zero parameter) constructor.
构造函数是我认为最好的方式。 如果这个实体必须是真正只读的(根本不允许在生产代码中创建新实例),您可以创建具有包访问权限的构造函数并仅在测试中使用它。 并且有可能即使您将默认构造函数设置为私有或具有包访问权限,您的持久性提供程序仍然能够使用此类实体,但不确定 - 请检查 eclipselink 文档。
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.
您可以模拟实体本身,提供您自己的 getter 实现吗?
您可以在模拟持久层中创建匿名扩展:
Can you just Mock the Entity itself, providing your own implemenations of the getters?
You could create an anonymous extension in your mock persistence layer:
您需要使用反射 API。 使用 Class.getField() 获取该字段,然后对该字段调用 setAccessable(true) 以便您可以写入该字段,即使它是私有的,最后您可以对其调用 set() 写入新值。
例如:
您希望将字段“i”设置为 3,即使它是私有的:
您需要处理许多异常。
You need to use the 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.
For example:
You want to set the field 'i' to 3, even though it is private:
There are a number of exceptions that you will need to handle.
您可以使用 Mockito 等测试库以读写模式访问对象内部状态。 例如,使用 Mockito 时:
You can use a test library like Mockito to access objects internal state in read and write mode. For example with Mockito use:
您可以使用 powermock 之类的模拟框架来绕过封装。 在 powermock 中,您可以使用
Whitebox.setInternalState(..)
设置私有成员。一种侵入性较小的方法是模拟 getter 方法。 这是否可行取决于内部状态的其他因素,但如果足够,那么它就是更干净的解决方案。
You can use a mocking framework like powermock to by pass encapsulation. In powermock you'd use
Whitebox.setInternalState(..)
to set a private member.A less invasive method would be to mock the getter method. Whether this is feasible would depend on what else depends on the internal state but if it is enough, it's the cleaner solution.