当前位置: 首页 > 知识库问答 >
问题:

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

子车征
2023-03-14

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

我目前的解决方案是:

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

这是可行的,但是感觉有点不优雅,尤其是必须手工编写所有的传递方法。

有没有更好的解决方案?

共有2个答案

汪信鸥
2023-03-14

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

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);
司寇星海
2023-03-14

从根本上说,您遇到了与尝试使用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创建了一个命名的动态类型,但几乎可以肯定的是,您不能侵入它并允许您的代码通过名称来创建它。这是因为对< code>mock的调用在Mockito的内部状态中注册了实例。

// BAD: Unlikely to work
@Test public void yourTest() {
  objectUnderTest.methodUnderTest(
      mock(Handler.class).getClass().getName());
  // ...
}
 类似资料:
  • 不过就是创建结构体的时候,根据每个对象的特征赋值不同的属性罢了 // 3.创建一个结构体变量 p1 := Person{"lnj", 33} per.say() p2 := Person{"zs", 18} per.Say()

  • 我有一个单例春豆,可以创建原型豆;这些是从字段中检索的: 现在我想为单例创建一个JUnit-Test: 但是可以理解的是,这并没有正确设置单例的< code>Provider。 有什么办法吗?我希望避免创建创建原型实例的Singleton Factory bean。 或者,对单例使用一个< code>@Lookup-factory方法是否很有可能?我还没有研究过这个。

  • 本文向大家介绍请你谈谈如何通过反射创建对象?相关面试题,主要包含被问及请你谈谈如何通过反射创建对象?时的应答技巧和注意事项,需要的朋友参考一下 考察点:类 - 方法1:通过类对象调用newInstance()方法,例如:String.class.newInstance() - 方法2:通过类对象的getConstructor()或getDeclaredConstructor()方法获得构造器(Co

  • 我正在Azure Kubernetes服务上工作。我正在通过门户成功创建AKS。但是,我需要通过ARM模板来完成。 如何使用ARM模板创建AK? 为此,我选择了link 但是,我收到的问题如下: 代码:InvalidTemplate 消息:部署模板验证失败:“模板资源”AKSsubnet/Microsoft。授权/36985XXX-XXXX-XXXX-XXXX-XXXX-5fb6b7ebXXXX“

  • 问题内容: 我需要通过运行设置服务器的脚本来添加cron作业。我目前正在使用Ubuntu。我可以使用,但这将打开一个编辑器来编辑当前的crontab。我想以编程方式执行此操作。 有可能这样做吗? 问题答案: Cron作业通常存储在每个用户的文件下 您要做的最简单的事情可能就是创建一个配置了作业的文本文件,然后将其复制到cron spool文件夹中,并确保它具有正确的权限(600)。

  • 我需要根据数据库查询的结果集创建可变数量的JSON对象和JSON数组。JSON格式看起来与以下用于谷歌图表的格式非常相似。 我的问题是,我觉得这应该是一个简单的答案,如何在for循环中创建多个具有唯一名称的JSON对象?我的尝试: