【问题标题】:How do you unit-test code that interacts with and instantiates third-party COM objects?您如何对与第三方 COM 对象交互和实例化的代码进行单元测试?
【发布时间】:2010-09-09 09:17:46
【问题描述】:

目前阻碍我全力投入单元测试的最大问题之一是,我编写的代码中有很大一部分严重依赖于来自不同来源的第三方 COM 对象,这些对象也倾向于相互交互(如果您需要知道,我正在使用几个帮助库为 Microsoft Office 编写加载项)。

我知道我可能应该使用模拟对象,但在这种情况下我应该怎么做呢?我可以看到,当我只需要传递对已经存在的对象的引用但我的一些例程自己实例化外部 COM 对象,然后有时将它们传递给来自不同库的其他外部 COM 对象时,这相对容易。

这里的最佳实践方法是什么?我是否应该让我的测试代码临时更改注册表中的 COM 注册信息,以便测试代码将实例化我的模拟对象之一?我应该注入修改后的类型库单元吗?还有哪些其他方法?

我会特别感谢 Delphi 的示例或工具,但我也会对更一般的建议和更高级别的解释感到满意。

谢谢,

奥利弗

【问题讨论】:

    标签: delphi unit-testing com mocking


    【解决方案1】:

    传统方法说您的客户端代码应该使用一个包装器,该包装器负责实例化 COM 对象。然后可以轻松地模拟此包装器。

    因为您的部分代码直接实例化了 COM 对象,所以这并不适合。如果您可以更改该代码,则可以使用工厂模式:他们使用工厂来创建 COM 对象。您可以模拟工厂以返回替代对象。

    是通过包装器还是通过原始 COM 接口访问对象取决于您。如果您选择模拟 COM 接口,请记住在您的模拟中检测 IUnknown::QueryInterface,这样您就知道您已经模拟了所有接口,特别是如果该对象随后被传递给其他一些 COM 对象。

    或者,查看CoTreateAsClass 方法。我从未使用过它,但它可能会满足您的需求。

    【讨论】:

      【解决方案2】:

      我会围绕您的第三方 COM 对象编写一个瘦包装类,它能够在单元测试情况下加载模拟对象而不是实际的 COM 对象。我通常通过调用第二个构造函数来传递模拟对象来做到这一点。普通的构造函数会像往常一样加载 COM 对象。

      维基百科文章对该主题有很好的介绍 Wikipedia artible

      【讨论】:

        【解决方案3】:

        归结为“为可测试性而设计”。理想情况下,您不应该直接实例化这些 COM 对象,而应该通过可以被模拟对象替换的间接层来访问它们。

        现在,COM 本身确实提供了一定程度的间接性,您可以提供一个模拟对象来替代真实对象,但我怀疑创建它会很痛苦,我怀疑您是否会从现有的模拟框架。

        【讨论】:

        • 同意;并且由于与 COM 对象的所有交互(通过 IDispatch 的自动化调用除外)都使用 COM 接口,因此您应该能够在模拟类中实现这些接口。
        猜你喜欢
        • 1970-01-01
        • 2020-06-22
        • 2012-06-20
        • 2023-03-17
        • 2020-06-06
        • 2013-12-12
        • 1970-01-01
        • 2017-04-09
        • 1970-01-01
        相关资源
        最近更新 更多