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
getMock()
方法访问objectUnderTest.getHandler().getMock()
来观察对象有更好的解决方案吗?基本上,您遇到的问题与使用
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);