简体   繁体   English

您如何对与第三方 COM 对象交互并实例化的代码进行单元测试?

[英]How do you unit-test code that interacts with and instantiates third-party COM objects?

One of the biggest issues currently holding me back from diving full steam into unit testing is that a really large percentage of the code I write is heavily dependent on third-party COM objects from different sources that also tend to interact with each other (I'm writing add-ins for Microsoft Office using several helper libraries if you need to know).目前阻碍我全力投入单元测试的最大问题之一是,我编写的代码中有很大一部分严重依赖于来自不同来源的第三方 COM 对象,这些对象也倾向于相互交互(I'如果您需要知道,我会使用几个帮助程序库为 Microsoft Office 编写加载项)。

I know I should probably use mock objects but how exactly would I go about that in this case?我知道我可能应该使用模拟对象,但在这种情况下,我究竟会如何 go 呢? I can see that it's relatively easy when I just have to pass a reference to an already existing object but some of my routines instantiate external COM objects themselves and then sometimes pass them on to some other external COM-object from yet a different library.我可以看到,当我只需要传递对已经存在的 object 的引用但我的一些例程自己实例化外部 COM 对象然后有时将它们传递给来自另一个库的其他一些外部 COM 对象时,这相对容易。

What is the best-practice approach here?这里的最佳实践方法是什么? Should I have my testing code temporarily change the COM registration information in the registry so the tested code will instantiate one of my mock objects instead?我是否应该让我的测试代码临时更改注册表中的 COM 注册信息,以便测试代码将实例化我的模拟对象之一? Should I inject modified type library units?我应该注入修改后的类型库单元吗? What other approaches are there?还有哪些其他方法?

I would be especially grateful for examples or tools for Delphi but would be just as happy with more general advice and higher-level explanations just as well.我将特别感谢 Delphi 的示例或工具,但我也会对更一般的建议和更高级别的解释感到满意。

Thanks,谢谢,

Oliver奥利弗

The traditional approach says that your client code should use a wrapper, which is responsible for instantiating the COM object.传统方法说您的客户端代码应该使用包装器,它负责实例化 COM object。 This wrapper can then be easily mocked.然后可以轻松地模拟此包装器。

Because you've got parts of your code instantiating the COM objects directly, this doesn't really fit.因为您的部分代码直接实例化了 COM 对象,所以这并不适合。 If you can change that code, you could use the factory pattern: they use the factory to create the COM object.如果您可以更改该代码,则可以使用工厂模式:他们使用工厂创建 COM object。 You can mock the factory to return alternative objects.您可以模拟工厂以返回替代对象。

Whether the object is accessed via a wrapper or via the original COM interface is up to you. object 是通过包装器还是通过原始 COM 接口访问取决于您。 If you choose to mock the COM interface, remember to instrument IUnknown::QueryInterface in your mock, so you know that you've mocked all of the interfaces, particularly if the object is then passed to some other COM object. If you choose to mock the COM interface, remember to instrument IUnknown::QueryInterface in your mock, so you know that you've mocked all of the interfaces, particularly if the object is then passed to some other COM object.

Alternatively, check out the CoTreateAsClass method.或者,查看CoTreatAsClass方法。 I've never used it, but it might do what you need.我从未使用过它,但它可能会满足您的需求。

It comes down to 'designing for testability'.它归结为“为可测试性而设计”。 Ideally, you should not instantiate those COM objects directly but should access them through a layer of indirection that can be replaced by a mock object.理想情况下,您不应直接实例化这些 COM 对象,而应通过可以被模拟 object 替换的间接层访问它们。

Now, COM itself does provide a level of indirection and you could provide a mock object that provided a substitute for the real one but I suspect it would be a pain to create and I doubt if you'd get much help from an existing mocking framework.现在,COM 本身确实提供了一定程度的间接性,您可以提供一个模拟 object 来替代真实的 object,但我怀疑创建它会很痛苦,我怀疑您是否会从现有的 ZD1892D850270BA228CC107BD20 框架中获得很多帮助.

I would write a thin wrapper class around your third party COM object, which has the ability to load a mock object rather than the actual COM object in the unit testing situation. I would write a thin wrapper class around your third party COM object, which has the ability to load a mock object rather than the actual COM object in the unit testing situation. I normally do this by having a second constructor that I call passing in the mock object.我通常通过第二个构造函数来实现这一点,我调用它传入模拟 object。 The normal constructor would have just loaded the COM object as normal.正常的构造函数会正常加载 COM object。

The wikipedia article has a good introduction to the subject Wikipedia artible wikipedia article对Wikipedia artible这个主题有很好的介绍

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM