使用Java/Mockito/PowerMockito使用私有构造函数实例化类

使用Java/Mockito/PowerMockito使用私有构造函数实例化类,java,junit,mockito,powermockito,Java,Junit,Mockito,Powermockito,我正在使用JUnit编写一个测试用例,测试中的方法使用带有私有构造函数的最终类作为参数。因为我不能用new关键字实例化它,所以我尝试使用Mockito但是发现Mockito不喜欢final类。我使用了PowerMockito,这对我来说似乎是合理的,但是PowerMockito.mockStatic(Field.class)是一个无效的方法,我需要一个字段的引用,以便在调用该方法时可以将其作为参数传递 我想捕获IllegalArgumentException,但首先我需要将字段的引用作为参数传递

我正在使用JUnit编写一个测试用例,测试中的方法使用带有私有构造函数的最终类作为参数。因为我不能用
new
关键字实例化它,所以我尝试使用
Mockito
但是发现
Mockito
不喜欢
final类。我使用了
PowerMockito
,这对我来说似乎是合理的,但是
PowerMockito.mockStatic(Field.class)
是一个无效的方法,我需要一个
字段
的引用,以便在调用该方法时可以将其作为参数传递

我想捕获
IllegalArgumentException
,但首先我需要将
字段的引用作为参数传递

测试中的方法

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(?);
}
我不知道该怎么做


提前感谢

我们实际上可以使用
核心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);
    }
私有字段;
@测试(预期=IllegalArgumentException.class)
public void testAccept()引发异常{
clazz类=Field.Class;
构造函数[]构造函数=clazz.getDeclaredConstructors();
对于(构造函数cons:constructors){
cons.setAccessible(true);
field=(field)cons.newInstance();
}
DefaultToStringBuilder=new DefaultToStringBuilder(新对象());
建造商验收(现场);
assertNotNull(建筑商);
}

我的答案不要那样做。不要仅仅因为生产代码无法通过其他方式进行测试而使用PowerMock

您很快就会发现,PowerMock产生的问题比它解决的问题还多

通常,使用PowerMock的需求来自于一个不完整的设计。因此,与其花费数小时通过PowerMock启用一个坏的测试设计。。。为了重新设计,您最好花一小部分时间。(从我的一次经历来看:PowerMock很快就会导致在上面花费无数个小时)


意思:您可以添加一个包保护的构造函数来进行测试。或者你可以更进一步了解更广泛的情况;并找到允许公共构造函数的方法;同时保持导致当前最终/私有实现的设计思想。

使用java反射从类外获取私有构造函数的对象。下面是一个例子

//示例类Student.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;
        }
    }
在下面的代码中,有两种方法可以实例化类
1-使用给定的构造函数名称和 实例化该类。 2-为给定数量的参数和 类型并实例化该类

        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");
            }
        } 
import java.lang.reflect.Constructor;
导入java.lang.reflect.InvocationTargetException;
导入java.lang.reflect.Modifier;
公共类PrivateConstructorDemo{
//使用给定的构造函数名称查找私有构造函数并实例化该类。
public void createObjectByConstructorName(int-id,字符串名)抛出NoSuchMethodException、SecurityException、,
实例化异常、IllegalAccessException、IllegalArgumentException、InvocationTargetException{
构造函数=Student.class.getDeclaredConstructor(Integer.class,String.class);
if(Modifier.isPrivate(constructor.getModifiers())){
constructor.setAccessible(true);
学生=(学生)构造函数.newInstance(id,名称);
System.out.println(“学生Id:+Student.getStudentId());
System.out.println(“学生名:+Student.getStudentName());
}
} 
//对于给定数量的参数和类型,并实例化该类。
public void createObject(int-id,String-name)抛出实例化异常,
IllegalAccessException、IllegalArgumentException、InvocationTargetException{
构造函数[]构造函数=Student.class.getDeclaredConstructors();
for(构造函数:构造函数){
if(Modifier.isPrivate(constructor.getModifiers())){
constructor.setAccessible(true);
类[]clazz=constructor.getParameterTypes();
if(constructor.getParameterCount()==2&&clazz[0]==Integer.class&&
clazz[1]==String.class){
Object ob=constructor.newInstance(id,name);
如果(学生的ob实例){
学生=(学生)ob;
System.out.println(“学生Id:+Student.getStudentId());
System.out.println(“学生名:+Student.getStudentName());
}
}
}
}
}
公共静态void main(字符串[]args)抛出实例化异常、IllegalAccessException、,
IllegalArgumentException、InvocationTargetException、NoSuchMethodException、SecurityException{
PrivateConstructorDemo obj=新的PrivateConstructorDemo();
对象createObject(10,“Sandeep”);
System.out.println(“---------------------------”);
对象createObjectByConstructorName(20,“Sandeep”);
}
} 
您已经检查过了吗?