使用 Java/Mockito/PowerMockito 使用私有构造函数实例化 Class
Instantiating a Class with private constructor using Java/Mockito/PowerMockito
我正在使用 JUnit
编写测试用例,被测方法采用最终的 class 并将私有构造函数作为参数。由于我无法使用 new
关键字实例化它,我尝试使用 Mockito
但发现 Mockito
不喜欢 final class
。我去使用 PowerMockito
这对我来说似乎是合理的,但 PowerMockito.mockStatic(Field.class);
是一个无效方法,我需要 Field
的引用,以便我可以在调用该方法时将其作为参数传递。
我想捕获 IllegalArgumentException
但首先我需要将 Field
的引用作为参数传递
正在测试的方法
public boolean accept(Field field) {
if( ignoreNulls ) {
try {
if( field.get( super.getObject() ) == null ) {
return false;
}
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
}
}
return super.accept(field);
}
JUnit 测试用例
@Test(expected=IllegalArgumentException.class)
public void testAccept() throws Exception {
DefaultToStringBuilder builder = new DefaultToStringBuilder(new Object());
PowerMockito.mockStatic(Field.class);
builder.accept(?);
}
我不确定我应该怎么做。
提前致谢
我们实际上可以使用Core Java
来实现这一点。下面的代码显示了如何做到这一点。
private Field field;
@Test(expected=IllegalArgumentException.class)
public void testAccept() throws Exception {
Class<?> clazz = Field.class;
Constructor<?> [] constructors = clazz.getDeclaredConstructors();
for(Constructor cons: constructors) {
cons.setAccessible(true);
field = (Field) cons.newInstance();
}
DefaultToStringBuilder builder = new DefaultToStringBuilder(new Object());
builder.accept(field);
assertNotNull(builder);
}
我的回答不要那样做。不要仅仅因为您的生产代码无法通过其他方式进行测试就使用 PowerMock。
您很快就会发现 PowerMock 制造的问题多于它解决的问题。
通常,需要使用 PowerMock 的原因是设计有缺陷。因此,与其花费数小时通过 PowerMock 来启用损坏的设计以进行测试,不如花一小部分时间来重新设计您的设计。 (根据我的一个经验:PowerMock 可以很快导致花费无数时间)
意思是:你可以添加一个包保护的构造函数来进行测试。或者您可以更进一步以了解更广泛的情况;并找到允许 public 构造函数的方法;同时保持导致当前 final/private 实施的设计理念。
使用 java 反射从外部 class 获取私有构造函数的对象。这是例子。
//样本classStudent.java
public class Student {
private Integer sudentId;
private String studentName;
private Student(){}
private Student(Integer studentId, String studentName) {
this.studentId = studentId;
this.studentName = studentName;
}
public Integer getStudentId() {
return studentId;
}
public String getStudentName() {
return studentName;
}
}
在下面的代码中,有两种方法可以实例化 class
1-使用给定的构造函数名称查找私有构造函数和
实例化 class。
2- 找到给定数量的参数的私有构造函数和
类型并实例化 class
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
public class PrivateConstructorDemo {
//Find the private constructor using given constructor name and instantiate the class.
public void createObjectByConstructorName(int id, String name) throws NoSuchMethodException, SecurityException,
InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
Constructor<Student> constructor = Student.class.getDeclaredConstructor(Integer.class, String.class);
if (Modifier.isPrivate(constructor.getModifiers())) {
constructor.setAccessible(true);
Student student = (Student)constructor.newInstance(id, name);
System.out.println("Student Id:"+ student.getStudentId());
System.out.println("Student Name:"+ student.getStudentName());
}
}
//For given number of arguments and types and instantiate the class.
public void createObject(int id, String name) throws InstantiationException,
IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Constructor<?>[] constructors = Student.class.getDeclaredConstructors();
for (Constructor<?> constructor : constructors) {
if (Modifier.isPrivate(constructor.getModifiers())) {
constructor.setAccessible(true);
Class<?>[] clazzs = constructor.getParameterTypes();
if (constructor.getParameterCount() == 2 && clazzs[0] == Integer.class &&
clazzs[1] == String.class) {
Object ob = constructor.newInstance(id, name);
if (ob instanceof Student) {
Student student = (Student)ob;
System.out.println("Student Id:"+ student.getStudentId());
System.out.println("Student Name:"+ student.getStudentName());
}
}
}
}
}
public static void main(String[] args) throws InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
PrivateConstructorDemo obj = new PrivateConstructorDemo();
obj.createObject(10, "Sandeep");
System.out.println("-------------------------");
obj.createObjectByConstructorName(20,"Sandeep");
}
}
我正在使用 JUnit
编写测试用例,被测方法采用最终的 class 并将私有构造函数作为参数。由于我无法使用 new
关键字实例化它,我尝试使用 Mockito
但发现 Mockito
不喜欢 final class
。我去使用 PowerMockito
这对我来说似乎是合理的,但 PowerMockito.mockStatic(Field.class);
是一个无效方法,我需要 Field
的引用,以便我可以在调用该方法时将其作为参数传递。
我想捕获 IllegalArgumentException
但首先我需要将 Field
的引用作为参数传递
正在测试的方法
public boolean accept(Field field) {
if( ignoreNulls ) {
try {
if( field.get( super.getObject() ) == null ) {
return false;
}
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
}
}
return super.accept(field);
}
JUnit 测试用例
@Test(expected=IllegalArgumentException.class)
public void testAccept() throws Exception {
DefaultToStringBuilder builder = new DefaultToStringBuilder(new Object());
PowerMockito.mockStatic(Field.class);
builder.accept(?);
}
我不确定我应该怎么做。
提前致谢
我们实际上可以使用Core Java
来实现这一点。下面的代码显示了如何做到这一点。
private Field field;
@Test(expected=IllegalArgumentException.class)
public void testAccept() throws Exception {
Class<?> clazz = Field.class;
Constructor<?> [] constructors = clazz.getDeclaredConstructors();
for(Constructor cons: constructors) {
cons.setAccessible(true);
field = (Field) cons.newInstance();
}
DefaultToStringBuilder builder = new DefaultToStringBuilder(new Object());
builder.accept(field);
assertNotNull(builder);
}
我的回答不要那样做。不要仅仅因为您的生产代码无法通过其他方式进行测试就使用 PowerMock。
您很快就会发现 PowerMock 制造的问题多于它解决的问题。
通常,需要使用 PowerMock 的原因是设计有缺陷。因此,与其花费数小时通过 PowerMock 来启用损坏的设计以进行测试,不如花一小部分时间来重新设计您的设计。 (根据我的一个经验:PowerMock 可以很快导致花费无数时间)
意思是:你可以添加一个包保护的构造函数来进行测试。或者您可以更进一步以了解更广泛的情况;并找到允许 public 构造函数的方法;同时保持导致当前 final/private 实施的设计理念。
使用 java 反射从外部 class 获取私有构造函数的对象。这是例子。
//样本classStudent.java
public class Student {
private Integer sudentId;
private String studentName;
private Student(){}
private Student(Integer studentId, String studentName) {
this.studentId = studentId;
this.studentName = studentName;
}
public Integer getStudentId() {
return studentId;
}
public String getStudentName() {
return studentName;
}
}
在下面的代码中,有两种方法可以实例化 class
1-使用给定的构造函数名称查找私有构造函数和
实例化 class。
2- 找到给定数量的参数的私有构造函数和
类型并实例化 class
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
public class PrivateConstructorDemo {
//Find the private constructor using given constructor name and instantiate the class.
public void createObjectByConstructorName(int id, String name) throws NoSuchMethodException, SecurityException,
InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
Constructor<Student> constructor = Student.class.getDeclaredConstructor(Integer.class, String.class);
if (Modifier.isPrivate(constructor.getModifiers())) {
constructor.setAccessible(true);
Student student = (Student)constructor.newInstance(id, name);
System.out.println("Student Id:"+ student.getStudentId());
System.out.println("Student Name:"+ student.getStudentName());
}
}
//For given number of arguments and types and instantiate the class.
public void createObject(int id, String name) throws InstantiationException,
IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Constructor<?>[] constructors = Student.class.getDeclaredConstructors();
for (Constructor<?> constructor : constructors) {
if (Modifier.isPrivate(constructor.getModifiers())) {
constructor.setAccessible(true);
Class<?>[] clazzs = constructor.getParameterTypes();
if (constructor.getParameterCount() == 2 && clazzs[0] == Integer.class &&
clazzs[1] == String.class) {
Object ob = constructor.newInstance(id, name);
if (ob instanceof Student) {
Student student = (Student)ob;
System.out.println("Student Id:"+ student.getStudentId());
System.out.println("Student Name:"+ student.getStudentName());
}
}
}
}
}
public static void main(String[] args) throws InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
PrivateConstructorDemo obj = new PrivateConstructorDemo();
obj.createObject(10, "Sandeep");
System.out.println("-------------------------");
obj.createObjectByConstructorName(20,"Sandeep");
}
}