【问题标题】:Instantiating a Class with private constructor using Java/Mockito/PowerMockito使用 Java/Mockito/PowerMockito 实例化具有私有构造函数的类
【发布时间】:2016-09-23 15:55:48
【问题描述】:

我正在使用JUnit 编写一个测试用例,并且被测方法采用带有私有构造函数的最终类作为参数。由于我无法使用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(?);
}

我不知道该怎么做。

提前致谢

【问题讨论】:

标签: java junit mockito powermockito


【解决方案1】:

我的回答不要那样做。不要仅仅因为无法测试您的生产代码而参与 PowerMock。

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

通常情况下,使用 PowerMock 的需求来自于损坏的设计。因此,与其花费数小时通过 PowerMock 来启用损坏的设计进行测试……您最好花费一小部分时间来重新设计您的设计。 (根据我的一次经验:PowerMock 很快就会导致花费无数小时)

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

【讨论】:

    【解决方案2】:

    我们实际上可以使用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);
        }
    

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-01-06
        • 1970-01-01
        • 2011-11-07
        • 2017-10-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多