8

有没有办法在 Java 中使用 JMock 来模拟对象构造?

例如,如果我有这样的方法:

public Object createObject(String objectType) {
    if(objectType.equals("Integer") {
        return new Integer();
    } else if (objectType.equals("String") {
        return new String();
    }
}

...有没有办法在测试方法中模拟对象构造的期望?

我希望能够期望调用某些构造函数,而不是使用额外的代码来检查类型(因为它并不总是像我的示例那样复杂和简单)。

所以而不是:

assertTrue(a.createObject() instanceof Integer);

我可以期望调用某个构造函数。只是为了让它更简洁一些,并以更易读的方式表达实际正在测试的内容。

请原谅这个简单的例子,我正在处理的实际问题有点复杂,但是有期望会简化它。


更多背景知识:

我有一个简单的工厂方法,它创建包装对象。被包装的对象可能需要在测试类中难以获得的参数(它是预先存在的代码),因此很难构造它们。

也许更接近我实际寻找的是:有没有一种方法可以一举模拟整个类(使用 CGLib),而无需指定要存根的每种方法?

所以 mock 被包装在一个构造函数中,所以显然可以在上面调用方法,JMock 是否能够动态地模拟出每个方法?

我的猜测是否定的,因为那会非常复杂。但是知道我在叫错树也很有价值:-)

4

6 回答 6

7

我唯一能想到的就是在工厂对象上使用 create 方法,而不是模拟。

但就模拟构造函数调用而言,没有。模拟对象以对象存在为前提,而构造函数以对象不存在为前提。至少在分配和初始化一起发生的java中。

于 2008-09-18T12:30:31.370 回答
4

jmockit 可以做到这一点。

在https://stackoverflow.com/questions/22697#93675​​中查看我的答案

于 2008-09-18T15:54:04.360 回答
1

唉,我想我问错了问题。

我试图测试的简单工厂看起来像:

public Wrapper wrapObject(Object toWrap) {
    if(toWrap instanceof ClassA) {
        return new Wrapper((ClassA) toWrap);
    } else if (toWrap instanceof ClassB) {
        return new Wrapper((ClassB) toWrap);
    } // etc

    else {
        return null;
    }
}

我问的问题是如何查找是否调用了“new ClassAWrapper()”,因为在孤立的测试中很难获得对象 toWrap。包装器(如果它甚至可以被称为)有点奇怪,因为它使用同一个类来包装不同的对象,只是使用不同的构造函数[1]。我怀疑如果我把这个问题问得更好一点,我很快就会得到答案:

“您应该模拟 Object toWrap 以匹配您在不同测试方法中测试的实例,并检查生成的 Wrapper 对象以找到返回的正确类型......并希望您足够幸运,您不必模拟世界以创建不同的实例;-)"

我现在有一个可以解决眼前问题的好方法,谢谢!

[1] 提出是否应该重构的问题完全超出了我当前问题的范围 :-)

于 2008-09-18T13:53:14.010 回答
0

你熟悉依赖注入吗?

如果不是,那么您肯定会从了解该概念中受益。我想 Martin Fowler 的古老的控制容器反转和依赖注入模式将作为一个很好的介绍。

使用依赖注入 (DI),您将拥有一个 DI 容器对象,它能够为您创建各种类。然后,您的对象将使用 DI 容器来实例化类,并且您将模拟 DI 容器以测试该类是否创建了预期类的实例。

于 2008-09-18T12:36:29.123 回答
0

依赖注入或控制反转。

或者,对您创建的所有对象使用抽象工厂设计模式。当您处于单元测试模式时,注入一个测试工厂,它将告诉您正在创建什么,然后在测试工厂中包含断言代码以检查结果(控制反转)。

为了使您的代码尽可能干净,请创建一个内部受保护的接口,将生产代码作为内部类实现接口(您的工厂)。添加初始化到默认工厂的接口的静态变量类型。为工厂添加静态设置器,您就完成了。

在您的测试代码中(必须在同一个包中,否则内部接口必须是公共的),使用断言代码和测试代码创建一个匿名或内部类。然后在您的测试中,初始化目标类,分配(注入)测试工厂,并运行目标类的方法。

于 2008-09-18T12:57:27.017 回答
-1

我希望没有。模拟应该模拟没有构造函数的接口......只有方法。

您在这里进行测试的方法似乎有些不对劲。为什么需要测试显式构造函数被调用的任何原因?
断言返回对象的类型对于测试工厂实现似乎没问题。将 createObject 视为一个黑盒。检查它返回的内容,但不要对它的执行方式进行微观管理。没有人喜欢这样:)

更新更新:哎哟!绝望时期的绝望措施是吗?如果 JMock 允许这样做,我会感到惊讶……正如我所说,它适用于接口……而不是具体类型。所以

  • 要么尝试花费一些精力来让那些讨厌的输入对象在测试工具下“可实例化”。在你的方法中自下而上。
  • 如果那不可行,请使用断点手动对其进行测试(我知道这很糟糕)。然后在源文件的可见区域中粘贴“触摸它,后果自负”评论并继续前进。再战一天。
于 2008-09-18T12:27:38.133 回答