繁体   English   中英

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

[英]Instantiating a Class with private constructor using Java/Mockito/PowerMockito

我正在使用JUnit编写一个测试用例,被测试的方法采用一个带有私有构造函数的最终类作为参数。 由于我无法使用new关键字实例化它,因此我尝试使用Mockito但发现Mockito不喜欢final class 我去使用PowerMockito这对我来说似乎合理,但是PowerMockito.mockStatic(Field.class); 是一个 void 方法,我需要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 很快就会导致花费在它上面的时间不计其数)

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

使用 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");
            }
        } 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM