在单元测试中使用反射是不好的做法吗?

2022-08-31 09:17:06

在过去的几年里,我一直认为在Java中,反射在单元测试中被广泛使用。由于必须检查的一些变量/方法是私有的,因此有必要以某种方式读取它们的值。我一直认为反射API也用于此目的。

上周我不得不测试一些软件包,因此编写了一些JUnit测试。一如既往,我使用Refperion来访问私有字段和方法。但是我的主管检查了代码,他对此并不满意,并告诉我Refleprem API不是用来进行这种“黑客攻击”的。相反,他建议修改生产代码中的可见性。

使用反射真的是不好的做法吗?我真的不敢相信——

编辑:我应该提到,我被要求所有测试都在一个名为test的单独包中(所以使用受保护的可见性,例如,也不是一个可能的解决方案)


答案 1

恕我直言,反射实际上应该只是最后的手段,保留给单元测试遗留代码的特殊情况或您无法更改的API。如果您正在测试自己的代码,那么您需要使用Reflectral的事实意味着您的设计是不可测试的,因此您应该修复它而不是诉诸Reflectm。

如果您需要在单元测试中访问私有成员,这通常意味着所讨论的类具有不合适的接口,和/或尝试执行太多操作。因此,要么修改其接口,要么将一些代码提取到单独的类中,其中可以公开那些有问题的方法/字段访问器。

请注意,通常使用反射会导致代码除了更难理解和维护外,还更加脆弱。在正常情况下,编译器会检测到一整组错误,但是使用Reflectle,它们仅作为运行时异常出现。

更新:正如@tackline所指出的,这只涉及在自己的测试代码中使用Reflectm,而不是测试框架的内部。JUnit(可能还有所有其他类似的框架)使用反射来识别和调用测试方法 - 这是对反射的合理和本地化使用。如果不使用反射,很难或不可能提供相同的功能和便利性。OTOH它完全封装在框架实现中,因此它不会使我们自己的测试代码复杂化或受到损害。


答案 2

仅仅为了测试而修改生产 API 的可见性真的很糟糕。出于正当理由,该可见性可能设置为其当前值,并且不会更改。

使用反射进行单元测试基本上没问题。当然,您应该针对可测试性设计类,以便减少反射需求。

例如,春天有.但它的目的是设置依赖性的模拟,春天应该在那里注入它们。ReflectionTestUtils

该主题比“做与不做”更深入,并且涉及应该测试的内容 - 是否需要测试对象的内部状态;我们是否应该对被测类的设计提出质疑;等。


推荐