如何使用JUnit测试具有内部私有方法、字段或嵌套类的类?
仅仅为了能够运行测试而更改方法的访问修饰符似乎是不好的。
如何使用JUnit测试具有内部私有方法、字段或嵌套类的类?
仅仅为了能够运行测试而更改方法的访问修饰符似乎是不好的。
当前回答
在您的课堂上:
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 ;)
}
其他回答
对于Java,我会使用反射,因为我不喜欢仅仅为了测试而更改对声明方法的包的访问。然而,我通常只测试公共方法,这也应该确保私有方法正常工作。
不能使用反射从所有者类外部获取私有方法,私有修饰符也会影响反射
这不是真的。你当然可以,正如塞姆·卡提卡斯的回答中所提到的。
当我的类中有足够复杂的私有方法,以至于我觉得需要直接测试私有方法时,这是一种代码气味:我的类太复杂了。
我解决这些问题的通常方法是梳理出一个包含有趣内容的新类。通常,这个方法及其交互的字段,或者可以将另一个或两个方法提取到一个新类中。
新类将这些方法公开为“public”,因此可以对它们进行单元测试。新的和旧的类现在都比原来的类简单,这对我来说很好(我需要保持简单,否则我会迷路!)。
注意,我并不是建议人们不用大脑就可以创建课程!这里的重点是使用单元测试的力量来帮助您找到好的新类。
如果您只使用Mockito:
您可以将私有方法视为正在测试的公共方法的一部分。您可以确保在测试公共方法时覆盖私有方法中的所有情况。
假设您是一个仅限Mockito的用户(不允许或不想使用PowerMock或反射或任何此类工具),并且不想更改正在测试的现有代码或库,这可能是最好的方法。
如果选择这种方式,唯一需要处理的就是在私有方法中本地声明的变量(用户定义的对象)。如果私有方法依赖于本地声明的变量对象及其方法,请确保将这些用户定义的对象全局声明为私有对象,而不是本地声明的对象。您可以在本地实例化这些对象。
这允许您模拟这些对象并将它们注入回测试对象。你也可以模仿(使用when/then)他们的方法。
这将允许您在测试公共方法时无错误地测试私有方法。
优势
代码覆盖范围能够测试完整的私有方法。
缺点
对象的作用域如果您不希望对象公开给同一类中的其他方法,这可能不是您的方式。当在不同的公共方法和/或在同一方法中多次调用时,您可能会多次测试私有方法。
这是我的龙目样本:
public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Student student = new Student();
Field privateFieldName = Student.class.getDeclaredField("name");
privateFieldName.setAccessible(true);
privateFieldName.set(student, "Naruto");
Field privateFieldAge = Student.class.getDeclaredField("age");
privateFieldAge.setAccessible(true);
privateFieldAge.set(student, "28");
System.out.println(student.toString());
Method privateMethodGetInfo = Student.class.getDeclaredMethod("getInfo", String.class, String.class);
privateMethodGetInfo.setAccessible(true);
System.out.println(privateMethodGetInfo.invoke(student, "Sasuke", "29"));
}
@Setter
@Getter
@ToString
class Student {
private String name;
private String age;
private String getInfo(String name, String age) {
return name + "-" + age;
}
}
在Spring Framework中,您可以使用以下方法测试私有方法:
ReflectionTestUtils.invokeMethod()
例如:
ReflectionTestUtils.invokeMethod(TestClazz, "createTest", "input data");