Java 如何测试私有函数或具有私有方法、字段或内部类的类?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/34571/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I test a private function or a class that has private methods, fields or inner classes?
提问by MattGrommes
How do I unit test (using xUnit) a class that has internal private methods, fields or nested classes? Or a function that is made private by having internal linkage(static
in C/C++) or is in a private (anonymous) namespace?
如何对具有内部私有方法、字段或嵌套类的类进行单元测试(使用 xUnit)?或者通过内部链接(static
在 C/C++ 中)或在私有(匿名)命名空间中的函数?
It seems bad to change the access modifier for a method or function just to be able to run a test.
为了能够运行测试而更改方法或函数的访问修饰符似乎很糟糕。
采纳答案by Cem Catikkas
Update:
Some 10 years later perhaps the best way to test a private method, or any inaccessible member, is via
@Jailbreak
from the Manifoldframework.@Jailbreak Foo foo = new Foo(); // Direct, *type-safe* access to *all* foo's members foo.privateMethod(x, y, z); foo.privateField = value;
This way your code remains type-safe and readable. No design compromises, no overexposing methods and fields for the sake of tests.
更新:
大约10年后,也许是为了测试一个私有方法,或任何无法访问的成员的最好方法,是通过
@Jailbreak
从歧管框架。@Jailbreak Foo foo = new Foo(); // Direct, *type-safe* access to *all* foo's members foo.privateMethod(x, y, z); foo.privateField = value;
这样你的代码就保持了类型安全和可读性。没有设计妥协,没有为了测试而过度曝光方法和领域。
If you have somewhat of a legacy Javaapplication, and you're not allowed to change the visibility of your methods, the best way to test private methods is to use reflection.
如果您有一些遗留Java应用程序,并且不允许您更改方法的可见性,那么测试私有方法的最佳方法是使用反射。
Internally we're using helpers to get/set private
and private static
variables as well as invoke private
and private static
methods. The following patterns will let you do pretty much anything related to the private methods and fields. Of course, you can't change private static final
variables through reflection.
在内部,我们使用助手来获取/设置private
和private static
变量以及调用private
和private static
方法。以下模式可以让你做几乎所有与私有方法和字段相关的事情。当然,你private static final
不能通过反射来改变变量。
Method method = TargetClass.getDeclaredMethod(methodName, argClasses);
method.setAccessible(true);
return method.invoke(targetObject, argObjects);
And for fields:
对于字段:
Field field = TargetClass.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);
Notes:
1.TargetClass.getDeclaredMethod(methodName, argClasses)
lets you look intoprivate
methods. The same thing applies forgetDeclaredField
.
2. ThesetAccessible(true)
is required to play around with privates.
注意事项:
1.TargetClass.getDeclaredMethod(methodName, argClasses)
让您查看private
方法。同样的事情适用于getDeclaredField
.
2.setAccessible(true)
需要与私人玩耍。
回答by Trumpi
The best way to test a private method is via another public method. If this cannot be done, then one of the following conditions is true:
测试私有方法的最佳方法是通过另一个公共方法。如果无法做到这一点,则以下条件之一为真:
- The private method is dead code
- There is a design smell near the class that you are testing
- The method that you are trying to test should not be private
- 私有方法是死代码
- 您正在测试的课程附近有一种设计气味
- 您尝试测试的方法不应该是私有的
回答by John Channing
Generally a unit test is intended to exercise the public interface of a class or unit. Therefore, private methods are implementation detail that you would not expect to test explicitly.
通常,单元测试旨在练习类或单元的公共接口。因此,私有方法是您不希望显式测试的实现细节。
回答by Thomas Owens
The private methods are called by a public method, so the inputs to your public methods should also test private methods that are called by those public methods. When a public method fails, then that could be a failure in the private method.
私有方法由公共方法调用,因此公共方法的输入还应测试由这些公共方法调用的私有方法。当公共方法失败时,那可能是私有方法的失败。
回答by Iker Jimenez
From this article: Testing Private Methods with JUnit and SuiteRunner(Bill Venners), you basically have 4 options:
从这篇文章:使用 JUnit 和 SuiteRunner(Bill Venners)测试私有方法,您基本上有 4 个选项:
- Don't test private methods.
- Give the methods package access.
- Use a nested test class.
- Use reflection.
- 不要测试私有方法。
- 授予方法包访问权限。
- 使用嵌套测试类。
- 使用反射。
回答by bmurphy1976
I tend not to test private methods. There lies madness. Personally, I believe you should only test your publicly exposed interfaces (and that includes protected and internal methods).
我倾向于不测试私有方法。存在着疯狂。就个人而言,我认为您应该只测试公开暴露的接口(包括受保护的和内部方法)。
回答by Josh Brown
For Java I'd use reflection, since I don't like the idea of changing the access to a package on the declared method just for the sake of testing. However, I usually just test the public methods which should also ensure the private methods are working correctly.
对于 Java,我会使用反射,因为我不喜欢仅仅为了测试而更改对声明方法上的包的访问的想法。但是,我通常只测试公共方法,这也应该确保私有方法正常工作。
you can't use reflection to get private methods from outside the owner class, the private modifier affects reflection also
您不能使用反射从所有者类外部获取私有方法,私有修饰符也会影响反射
This is not true. You most certainly can, as mentioned in Cem Catikkas's answer.
这不是真的。正如Cem Catikkas 的回答中提到的那样,您当然可以。
回答by Grundlefleck
Having tried Cem Catikkas' solution using reflectionfor Java, I'd have to say his was a more elegant solution than I have described here. However, if you're looking for an alternative to using reflection, and have access to the source you're testing, this will still be an option.
在使用Java反射尝试了 Cem Catikkas 的解决方案后,我不得不说他的解决方案比我在这里描述的更优雅。但是,如果您正在寻找使用反射的替代方法,并且可以访问您正在测试的源,那么这仍然是一个选择。
There is possible merit in testing private methods of a class, particularly with test-driven development, where you would like to design small tests before you write any code.
测试类的私有方法可能有好处,特别是在测试驱动开发中,您希望在编写任何代码之前设计小测试。
Creating a test with access to private members and methods can test areas of code which are difficult to target specifically with access only to public methods. If a public method has several steps involved, it can consist of several private methods, which can then be tested individually.
创建可以访问私有成员和方法的测试可以测试难以专门针对仅访问公共方法的代码区域。如果一个公共方法涉及多个步骤,它可以由多个私有方法组成,然后可以单独测试。
Advantages:
好处:
- Can test to a finer granularity
- 可以测试到更细的粒度
Disadvantages:
缺点:
- Test code must reside in the same file as source code, which can be more difficult to maintain
- Similarly with .class output files, they must remain within the same package as declared in source code
- 测试代码必须与源代码位于同一个文件中,这可能更难维护
- 与 .class 输出文件类似,它们必须保留在与源代码中声明的相同的包中
However, if continuous testing requires this method, it may be a signal that the private methods should be extracted, which could be tested in the traditional, public way.
但是,如果连续测试需要这种方法,则可能是应该提取私有方法的信号,可以通过传统的公共方式进行测试。
Here is a convoluted example of how this would work:
这是一个令人费解的例子,说明了它是如何工作的:
// Import statements and package declarations
public class ClassToTest
{
private int decrement(int toDecrement) {
toDecrement--;
return toDecrement;
}
// Constructor and the rest of the class
public static class StaticInnerTest extends TestCase
{
public StaticInnerTest(){
super();
}
public void testDecrement(){
int number = 10;
ClassToTest toTest= new ClassToTest();
int decremented = toTest.decrement(number);
assertEquals(9, decremented);
}
public static void main(String[] args) {
junit.textui.TestRunner.run(StaticInnerTest.class);
}
}
}
The inner class would be compiled to ClassToTest$StaticInnerTest
.
内部类将被编译为ClassToTest$StaticInnerTest
.
See also: Java Tip 106: Static inner classes for fun and profit
回答by Don Kirkby
If you're trying to test existing code that you're reluctant or unable to change, reflection is a good choice.
如果您正在尝试测试您不愿意或无法更改的现有代码,反射是一个不错的选择。
If the class's design is still flexible, and you've got a complicated private method that you'd like to test separately, I suggest you pull it out into a separate class and test that class separately. This doesn't have to change the public interface of the original class; it can internally create an instance of the helper class and call the helper method.
如果类的设计仍然很灵活,并且您有一个复杂的私有方法要单独测试,我建议您将其拉出一个单独的类并单独测试该类。这不必更改原始类的公共接口;它可以在内部创建 helper 类的实例并调用 helper 方法。
If you want to test difficult error conditions coming from the helper method, you can go a step further. Extract an interface from the helper class, add a public getter and setter to the original class to inject the helper class (used through its interface), and then inject a mock version of the helper class into the original class to test how the original class responds to exceptions from the helper. This approach is also helpful if you want to test the original class without also testing the helper class.
如果您想测试来自辅助方法的困难错误条件,您可以更进一步。从helper 类中提取一个接口,在原类中添加一个公共的getter 和setter 来注入helper 类(通过它的接口使用),然后在原类中注入一个mock 版本的helper 类来测试原类如何响应来自助手的异常。如果您想测试原始类而不测试辅助类,这种方法也很有用。