目前阻碍我全力投入单元测试的一个最大问题是,我写的很大一部分代码在很大程度上依赖于来自不同来源的第三方COM对象,这些对象也倾向于互相交互(如果您需要了解,我正在使用几个帮助程序库为Microsoft Office编写加载项。)
我知道我应该使用模拟对象,但在这种情况下我究竟会怎么做呢?我可以看到,当我必须传递对已经存在的对象的引用时相对容易,但是我的一些例程本身实例化外部COM对象,然后有时将它们传递给来自不同库的其他外部COM对象。 / p>
这里的最佳做法是什么?我是否应该让我的测试代码暂时更改注册表中的COM注册信息,以便测试的代码将实例化我的一个模拟对象?我应该注入修改后的类型库单位吗?还有其他什么方法?
我会特别感谢Delphi的示例或工具,但同样会对更一般的建议和更高层次的解释感到满意。
谢谢,
奥利弗
答案 0 :(得分:6)
传统的方法是说你的客户端代码应该使用一个包装器,它负责实例化COM对象。然后可以很容易地模拟这个包装器。
因为你有部分代码直接实例化COM对象,所以这并不适合。如果您可以更改该代码,则可以使用工厂模式:它们使用工厂来创建COM对象。您可以模拟工厂以返回替代对象。
是通过包装器还是通过原始COM接口访问对象取决于您。如果您选择模拟COM接口,请记住在模拟中检测IUnknown :: QueryInterface,因此您知道您已经模拟了所有接口,特别是如果该对象随后被传递给其他COM对象。
或者,查看CoTreateAsClass方法。我从未使用它,但它可能会做你需要的。
答案 1 :(得分:3)
归结为'可测试性设计'。理想情况下,您不应直接实例化这些COM对象,而应通过可由模拟对象替换的间接层访问它们。
现在,COM本身确实提供了一个间接级别,你可以提供一个模拟对象,提供真正的替代,但我怀疑创建是一个痛苦,我怀疑你是否得到了一个很大的帮助现有的模拟框架。
答案 2 :(得分:2)
我会围绕你的第三方COM对象编写一个瘦的包装类,它能够在单元测试情况下加载模拟对象而不是实际的COM对象。我通常通过在mock对象中调用传递的第二个构造函数来完成此操作。普通构造函数将正常加载COM对象。
维基百科文章对该主题有一个很好的介绍 Wikipedia artible