2

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

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

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

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

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

我无法将自己的对象传递给“myPluginFunction”,我需要第三方对象类型的东西。如果我定义一个接口,我无权访问 ThirdPartyObject 来指定它实现该接口。我不能继承 ThirdPartyObject 并使用通用参数 ( <? extends ThirdPartyObject>),因为我的插件正在实现一个接口,所以我的参数类型受到限制。我研究了 Mocking,虽然很有趣,但它似乎不适用于我的情况。

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

4

2 回答 2

2

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

你可以嘲笑ThirdPartyObject. 事实上,如果你想做的是单元测试,你必须模拟。ThirdPartyObject

只需创建一个与 具有相同 FQN 的类ThirdPartyObject,但将其保存在您的测试文件夹中,这样它就不会被分发。

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

于 2013-08-25T12:45:52.553 回答
2

最好能够构造一个真实的ThirdPartyObject.

由于您需要引用此类,因此您的类路径中至少有一些包含此类的第 3 方库。您确定没有办法构建它,例如使用图书馆中的工厂吗?或者通过构造另一个对象并调用一个方法,该方法将使用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化,因为插件实现了一个接口,该接口具有ThirdPartyObjectas 方法参数而不是? extends ThirdPartyObject. 我不明白为什么会出现问题:采用ThirdPartyObjectas 参数的方法将很乐意采用ThirdPartyObject.

于 2013-08-25T14:20:14.507 回答