单元测试时如何处理第三方依赖关系

时间:2013-08-25 12:38:51

标签: java unit-testing junit

我正在为专有应用程序开发插件。

规范本质上是我有具有指定名称的函数。安装后,父应用程序将调用我的插件中的函数 - 传递各种参数。

我想对我的插件进行单元测试,但我无法访问父应用程序的源代码。我无法实例化测试我的函数所需的参数。

在这种特殊情况下,我的参数是一个对象,它有两个我访问的数据元素和一个我访问的日志记录功能。模拟样本并不会太困难,但我面临着一个两难的境地......

public PerSpecResponseObject myPluginFunction(ThirdPartyObject iUseThis){
...
}

我无法将自己的对象传递给“myPluginFunction”,我需要一些类型为ThirdPartyObject的东西。如果我定义了一个接口,我就无法访问ThirdPartyObject来指定它实现接口。我不能继承ThirdPartyObject并使用泛型参数(<? extends ThirdPartyObject>),因为我的插件正在实现一个接口,因此我的参数类型受到限制。我看着Mocking而有趣的是,它似乎不适用于我的情况。

这种情况有哪些解决方案?

2 个答案:

答案 0 :(得分:1)

如果您有权访问父应用程序的源代码,那么您将不会进行单元测试,而是进行集成测试。

你可以模仿ThirdPartyObject。事实上,如果您想要做的是单元测试,必须模拟ThirdPartyObject

只需创建一个与ThirdPartyObject具有相同FQN的类,但将其保存在测试文件夹中,以免分发。

这是我能想到的最简单的。

答案 1 :(得分:1)

能够构建真实的ThirdPartyObject确实是最好的。

由于您需要引用此类,因此您的类路径中至少包含一些包含此类的第三方库。 你确定没有办法构建它,例如使用同样在图书馆的工厂?或者通过构造另一个对象并调用一个方法,该方法将使用ThirdPartyObject实例调用您的插件?

虽然这是有时称为集成测试(因为您正在测试与主应用程序的集成),但只要测试没有,它也可以在经典意义上进行单元测试例如将数据放入数据库或做任何可能影响其他测试的事情。

如果上述情况不可能,您可以采用嘲弄ThirdPartyObject,例如使用 Mockito 。尽量确保您的测试代码不再与您的实现相结合。有些人认为他们需要模拟一个类的所有依赖项,然后验证对这些依赖项的所有方法调用。他们引入了很多强大的耦合和冗余。

关于你提到的两个问题,有两种方法:

1)你说你不能让ThirdPartyObject实现一个接口。这是真的,但您可以编写一个实现此接口的适配器并委托给ThirdPartyObject。然后,主应用程序调用的方法将简单地委托给使用此接口的实际插件方法实现。

示例(假设ThirdPartyObject只有一个方法void thirdPartyMethodCall()

public interface InterfaceForThirdPartyObject {
    void thirdPartyMethodCall();
}

public class ThirdPartyObjectAdapter implements InterfaceForThirdPartyObject {
    private final ThirdPartyObject delegate;

    public ThirdPartyObjectAdapter(ThirdPartyObject delegate) {
        this.delegate = delegate;
    }

    public void thirdPartyMethodCall() {
        delegate.thirdPartyMethodCall();
    }
}

// your actual plugin implementation, not directly exposed to the main app
public class MyPlugin {
    public PerSpecResponseObject myPluginFunction(InterfaceForThirdPartyObject iUseThis){
        // this will contain your actual logic that you want to test
    }
}

// this is the plugin as exposed to the main app
public class MyPluginAdapter implements PluginInterface {
    private final MyPlugin delegate = new MyPlugin();

    // this is called by the main application
    public PerSpecResponseObject myPluginFunction(ThirdPartyObject iUseThis) {
        delegate.myPluginFunction(new ThirdPartyObjectAdapter(iUseThis));
    }
}

2)你说你不能继承ThirdPartyObject,因为插件实现的接口有ThirdPartyObject作为方法参数而不是? extends ThirdPartyObject。我不明白为什么会出现这个问题:一个以ThirdPartyObject为参数的方法很乐意接受ThirdPartyObject的任何子类的实例。