Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/307.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何模拟通过Class.newInstance(className)创建的对象?_Java_Unit Testing_Mockito - Fatal编程技术网

Java 如何模拟通过Class.newInstance(className)创建的对象?

Java 如何模拟通过Class.newInstance(className)创建的对象?,java,unit-testing,mockito,Java,Unit Testing,Mockito,我试图将单元测试添加到一些遗留代码中,这些代码传递了一个字符串类名,并使用class.newInstance(字符串类名)创建了一个实现特定处理程序接口的对象。我可以控制传递的类名,可以获取指向新处理程序对象的指针(通过getHandler()调用),并且我希望使用Mockito观察对它的调用 我目前的解决办法是: 创建一个实现接口的新测试类TestHandler 让该测试类包含一个Mockito mock对象,该对象也实现该接口 手动将所有接口方法传递给模拟对象 使模拟对象可以通过getMoc

我试图将单元测试添加到一些遗留代码中,这些代码传递了一个字符串类名,并使用
class.newInstance(字符串类名)
创建了一个实现特定处理程序接口的对象。我可以控制传递的类名,可以获取指向新处理程序对象的指针(通过
getHandler()
调用),并且我希望使用Mockito观察对它的调用

我目前的解决办法是:

  • 创建一个实现接口的新测试类
    TestHandler
  • 让该测试类包含一个Mockito mock对象,该对象也实现该接口
  • 手动将所有接口方法传递给模拟对象
  • 使模拟对象可以通过
    getMock()
    方法访问
  • 通过调用
    objectUnderTest.getHandler().getMock()
    来观察对象
  • 这是可行的,但感觉有点不雅观,尤其是必须手动编写所有的pass-thru方法


    有更好的解决方案吗?

    基本上,您遇到的问题与使用
    new
    测试新创建的实例时遇到的问题相同;
    Class.newInstance
    (可能正确地说是
    Class.forName(foo).newInstance()
    )不会伤害您,但也不会帮助您

    作为旁注,您的
    TestHandler
    听起来像是一个通用的委托实现,它听起来非常有用(特别是当您需要编写处理程序包装器时)。如果是,您可能希望将其提升为与生产代码树中的处理程序相邻

    虽然我知道您提到了遗留代码,但如果允许您重构以包含测试接缝,这将变得非常容易。(为了便于解释,此处忽略反射异常。)

    您还可以提取对象创建并在测试中替换它:

    /** Instance field, package-private to replace in tests. */
    Function<String, Handler> instanceCreator =
        ( x -> (Handler) Class.forName(x).newInstance());
    
    public ReturnType yourMethodUnderTest(String className) {
      Handler handler = instanceCreator.apply(className);
      // ...
    }
    
    public ReturnType yourMethodUnderTest(String className) {
      Handler handler = createHandler(className);
      // ...
    }
    
    /** Package private for testing. */
    Handler createHandler(String className) {
      return Class.forName(className).newInstance();
    }
    
    @Test public void yourTest() {
      // Manually replace createHandler. You could also use a Mockito spy here.
      ObjectUnderTest objectUnderTest = new ObjectUnderTest() {
        @Override Handler createHandler(String className) {
          return mock(Handler.class);
        }
      }
      // ...
    }
    

    旁注:尽管Mockito创建了一个命名的动态类型,但几乎可以肯定的是,您将无法将其破解并允许您的代码按名称创建它。这是因为调用
    mock


    创建一个公共方法,在其中放置逻辑以获取类的新实例

    ClassA objectClassA=createNewInstance(className);
    
    同样,以及

    public ClassA createInstance(String className){
     return (ClassA) (Class.forName(className)).newInstance();
    }
    
    现在假设我们正在ClassB中创建classA的一个实例 然后在B的TestClass中,我们可以简单地模拟这个createInstance方法

    doReturn(mockClassA).when(mockClassB).createInstance(className);
    

    你到底想测试什么?调用某个方法时是否创建了正确运行时类型的实例?我想验证在新创建的对象上是否调用了方法。谢谢,这似乎是一个很好的方法,可以在我完成单元测试后继续前进并进行重构,这将允许我删除我关心的模拟对象包装器。
    public ClassA createInstance(String className){
     return (ClassA) (Class.forName(className)).newInstance();
    }
    
    doReturn(mockClassA).when(mockClassB).createInstance(className);