如何使用JUnit测试具有内部私有方法、字段或嵌套类的类?
仅仅为了能够运行测试而更改方法的访问修饰符似乎是不好的。
如何使用JUnit测试具有内部私有方法、字段或嵌套类的类?
仅仅为了能够运行测试而更改方法的访问修饰符似乎是不好的。
当前回答
要用大型而古怪的类测试遗留代码,能够测试我现在正在编写的一个私有(或公共)方法通常非常有用。
我在Java中使用junitx.util.PrivateAccessor包。它有很多用于访问私有方法和私有字段的有用的一行程序。
import junitx.util.PrivateAccessor;
PrivateAccessor.setField(myObjectReference, "myCrucialButHardToReachPrivateField", myNewValue);
PrivateAccessor.invoke(myObjectReference, "privateMethodName", java.lang.Class[] parameterTypes, java.lang.Object[] args);
其他回答
在您的课堂上:
namespace my_namespace {
#ifdef UNIT_TEST
class test_class;
#endif
class my_class {
public:
#ifdef UNIT_TEST
friend class test_class;
#endif
private:
void fun() { cout << "I am private" << endl; }
}
}
在单元测试类中:
#ifndef UNIT_TEST
#define UNIT_TEST
#endif
#include "my_class.h"
class my_namespace::test_class {
public:
void fun() { my_obj.fun(); }
private:
my_class my_obj;
}
void my_unit_test() {
test_class test_obj;
test_obj.fun(); // here you accessed the private function ;)
}
在尝试了Cem Catikkas使用Java反射的解决方案后,我不得不说,他的解决方案比我在这里描述的更优雅。然而,如果您正在寻找使用反射的替代方案,并且能够访问您正在测试的源代码,那么这仍然是一个选项。
测试类的私有方法可能有好处,特别是在测试驱动开发中,您希望在编写任何代码之前设计小型测试。
创建一个可以访问私有成员和方法的测试,可以测试那些只访问公共方法而难以专门针对的代码区域。如果公共方法涉及多个步骤,它可以由多个私有方法组成,然后可以单独测试。
优势:
可以测试到更精细的粒度
缺点:
测试代码必须位于文件作为源代码更难维护与.class输出文件类似,它们必须保持在源代码中声明的相同包中
然而,如果连续测试需要这种方法,这可能是一个信号,表明应该提取私有方法,可以以传统的公共方式进行测试。
下面是一个复杂的例子,说明这是如何工作的:
// 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);
}
}
}
内部类将编译为ClassToTest$StaticInnerTest。
另请参阅:Java提示106:静态内部类以获取乐趣和利润
正如其他人所说。。。不要直接测试私有方法。以下是一些想法:
保持所有方法的规模和重点(易于测试,易于发现错误)使用代码覆盖工具。我喜欢Cobertura(哦,快乐的一天,它看起来像是一个新版本!)
在单元测试上运行代码覆盖率。如果您发现方法没有经过充分测试,请添加到测试中以提高覆盖率。目标是100%的代码覆盖率,但要意识到你可能无法做到这一点。
私有方法由公共方法调用,因此公共方法的输入也应测试这些公共方法调用的私有方法。当公共方法失败时,这可能是私有方法的失败。
如果您只使用Mockito:
您可以将私有方法视为正在测试的公共方法的一部分。您可以确保在测试公共方法时覆盖私有方法中的所有情况。
假设您是一个仅限Mockito的用户(不允许或不想使用PowerMock或反射或任何此类工具),并且不想更改正在测试的现有代码或库,这可能是最好的方法。
如果选择这种方式,唯一需要处理的就是在私有方法中本地声明的变量(用户定义的对象)。如果私有方法依赖于本地声明的变量对象及其方法,请确保将这些用户定义的对象全局声明为私有对象,而不是本地声明的对象。您可以在本地实例化这些对象。
这允许您模拟这些对象并将它们注入回测试对象。你也可以模仿(使用when/then)他们的方法。
这将允许您在测试公共方法时无错误地测试私有方法。
优势
代码覆盖范围能够测试完整的私有方法。
缺点
对象的作用域如果您不希望对象公开给同一类中的其他方法,这可能不是您的方式。当在不同的公共方法和/或在同一方法中多次调用时,您可能会多次测试私有方法。