如何对扩展/继承第三方类的类进行单元测试

时间:2012-06-11 09:58:00

标签: java unit-testing jmock sitemesh

我创建了一个扩展第三方抽象类的新类。新类调用抽象类中的方法。我遇到的问题是在尝试编写单元测试时,我不确定如何编写测试,因为我不知道第三方类需要的确切细节。

下面的AbstractDecoratorMapper是一个SiteMesh特定类,我必须扩展它以使SiteMesh正常工作。据我所知,从文档中我不能使用合成。

public final class PartnerDecoratorMapper extends AbstractDecoratorMapper {

    @Override
    public void init(Config config, Properties properties, DecoratorMapper parent) throws InstantiationException {
        super.init(config, properties, parent);
    }

    @Override
    public Decorator getDecorator(HttpServletRequest request, Page page) {
        if (super.getDecorator(request, page).getName().equalsIgnoreCase("default")) {
            return getNamedDecorator(request, "externalPartnerDefault");
        }
        return super.getDecorator(request, page);
    }
}

如果此工具可以提供任何帮助,我会使用JMock。

4 个答案:

答案 0 :(得分:4)

你不需要知道来自第三方库的细节......你只需要模仿他们返回你期望的东西。

如果你继承它,你可以设置类,因为它将在生产中使用,并调用应该在常规使用中调用的方法。您需要检查的是结果是否符合您的预期。 (您无需确切知道第三方类如何在测试中工作)。

为了检查您实施的所有代码是否已执行,您可以使用插件检查覆盖范围,例如eclemma - http://www.eclemma.org/

答案 1 :(得分:3)

使用JMock,你不能尽我所知模拟对被测试类的超类的调用。

this related question的答案可能有用,但主要答案是切换到支持此功能的模拟框架(JMockit)。

答案 2 :(得分:1)

您可能会问两件事。我会尝试回答这两个问题。

可能的问题1)如何测试我的附加功能?

可能的问题2)如何测试组合功能是否合适?

让我先从问题1开始。

我建议简单的剥皮。这里有一个技术视频:http://www.youtube.com/watch?v=p0tILwRZH5Q (视频是c#但在java中基本相同)

这意味着之后您将拥有以下代码

@Override
public Decorator getDecorator(HttpServletRequest request, Page page) {
    Decorator d = super.getDecorator(request, page);
    return getResolvedDecorator(d, d.getName(), request);

}
public Decorator getResolvedDecorator(Decorator current, String name, HttpServletRequest request) {
    if (name.equalsIgnoreCase("default")) {
        return getNamedDecorator(request, "externalPartnerDefault");
    }
    return current;
}

现在你可以通过像

之类的调用来测试它
assertEquals(expected, new PartnerDecoratorMapper().getResolvedDecorator(null, "default", MockHttpServletRequest);

我建议也可以从HttpServletRequest中删除数据,以进行测试和测试。意图更清晰。

注意:这具有额外的性能优势,即对super.getDecorator()的调用只发生一次,因为结果是缓存的。

附加说明:值得注意的是,init()的覆盖是不必要的,实际上并没有做任何事情。

问题2:这是一个更难的问题,因为您没有说明所需的行为是什么。 我假设这是一个工厂模式,所以很可能它会以某种方式工作,如

| http请求质量1 |页面质量1 |期待装饰者| | / mypath / mypage | status = foo | MyDecorator |

(我不知道上面的图表应包含或看起来像什么) 一旦你有这种行为,那么测试将确保它是相当直接的。

快乐测试, 卢埃林

答案 3 :(得分:1)

  

因为我不知道第三方课要求的具体细节

任何类型的测试都会比较实际所做的事情与应该要做的事情。在你知道应该做什么之前你不能测试:“第三部分课程需要什么”。

如果您不知道基类需要什么,那么如何合理地尝试编写派生类?您要扩展的课程的API文档是什么?

问题可能是没有这样的API文档,或者它没有信息吗?可能是,虽然该类不是final,但它实际上并不打算用作基类。其中任何一个都表明设计不佳的API,并建议您不要打扰使用它

或者您不知道确切详细信息的关键难点?这可能是您的方法中的一个缺陷:通常您不能也不能对完全详细信息做出假设。您的代码应该符合文档化的API,并且您不应该假设任何未在文档化的API中声明的内容。这可能意味着您无法知道何时可以调用模板方法或将值传递给它们。如果基类通过传递声明为实现interface或非final类的对象(即,它们的类型而不是它们的<)来与模板方法进行通信指定了em> class ,你无法知道这些对象将具有哪个类。