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



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

我目前的解决方案是:

  1. 创建一个实现接口的新测试类TestHandler
  2. 让该测试类包含一个也实现接口的 Mockito 模拟对象。
  3. 手动将所有接口方法传递给模拟对象。
  4. 使模拟对象可通过getMock()方法访问。
  5. 通过对 objectUnderTest.getHandler().getMock() 进行 verify(( 调用来观察对象。

这有效,但感觉有点不优雅,尤其是必须手动编写所有直通方法。

有没有更好的解决方案?

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

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

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

public ReturnType yourMethodUnderTest(String className) {
  return yourMethodUnderTest(Class.newInstance(className));
}
/** Package private for testing. */
public ReturnType yourMethodUnderTest(Handler handler) {
  return yourMethodUnderTest(Class.newInstance(className));
}

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

/** 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 的调用在 Mockito 的内部状态中注册了实例。

// BAD: Unlikely to work
@Test public void yourTest() {
  objectUnderTest.methodUnderTest(
      mock(Handler.class).getClass().getName());
  // ...
}

创建一个公共方法,您将在其中放置逻辑以获取类的 newInstance

ClassA objectClassA=createNewInstance(className);

同样,和

public ClassA createInstance(String className){
 return (ClassA) (Class.forName(className)).newInstance();
}

现在假设我们在 ClassB 内部创建一个类 A 的实例那么在 B 的 TestClass 中,我们可以简单地模拟这个 createInstance 方法

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

相关内容

  • 没有找到相关文章

最新更新