如何模拟对象构造?

时间:2008-09-18 12:16:14

标签: java tdd junit mocking

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

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

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

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

我希望能够预期某些构造函数被调用,而不是需要额外的代码来检查类型(因为它不会像我的例子一样复杂和简单)。 / p>

所以而不是:

assertTrue(a.createObject() instanceof Integer);

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

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


更多背景知识:

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

也许接近我真正想要的是:有没有一种方法可以一次性模拟整个类(使用CGLib),而没有指定每个方法来存根?

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

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

6 个答案:

答案 0 :(得分:6)

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

但是在模拟构造函数调用方面,没有。模拟对象预先假定对象的存在,而构造函数预先假定对象不存在。至少在java中,分配和初始化一起发生。

答案 1 :(得分:4)

jmockit可以做到这一点。

https://stackoverflow.com/questions/22697#93675

中查看我的回答

答案 2 :(得分: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;
    }
}

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

“你应该模拟Object toWrap以匹配你在不同测试方法中测试的实例,并检查生成的Wrapper对象以找到正确的类型返回...并希望你很幸运,你不要我必须模仿世界来创造不同的实例;-)“

我现在对即时问题有一个好的解决方案,谢谢!

[1]提出这是否应该重构的问题远远超出了我目前的问题范围: - )

答案 3 :(得分:0)

您熟悉Dependency Injection吗?

如果不是,那么你就会从了解这个概念中获益。我想马丁福勒的好老Inversion of Control Containers and the Dependency Injection pattern将作为一个很好的介绍。

使用依赖注入(DI),您将拥有一个DI容器对象,它可以为您创建各种类。然后你的对象将使用DI容器来实例化类,你将模拟DI容器来测试该类创建期望类的实例。

答案 4 :(得分:0)

依赖注入或控制反转。

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

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

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

答案 5 :(得分:-1)

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

在这里测试的方法似乎有些不对劲。您需要测试显式构造函数的任何原因被调用吗? 断言返回对象的类型似乎可以用于测试工厂实现。将createObject视为黑盒子..检查它返回的内容,但不要微观管理它是如何做到的。没人喜欢:))

更新更新:哎哟!绝望的绝望措施啊?如果JMock允许的话,我会感到惊讶......因为我说它适用于接口......而不是具体的类型。 所以

  • 尝试并花费一些精力在测试工具下获取那些讨厌的输入对象'instantiable'。在你的方法中自下而上。
  • 如果这是不可行的,请用断点手动测试它(我知道它很糟糕)。然后在源文件的可见区域中粘贴“触摸它,风险自负”评论并继续前进。再战斗一天。
相关问题