Thoughts on testing COM objects

Ben over at Code Circle is thinking about unit testing COM objects. I did quite a lot of this back in 2000 when I was working with an investment bank. The first thing you need to realise is that COM is just an interface layer; so lots of your unit testing should be done on the code that the COM interface layer calls into. You can test pretty much all of the actual functionality of a COM object without bringing COM into the mix at all. This keeps the tests nice and fast.

So, rule one for testing COM objects is: Test as much as you can using normal unit testing techniques for the object implementation language.

Once you’ve done that you can start thinking about what it means to test a COM object…

I wrote my COM object tests as a C++ project that could be worked on in a separate instance of Visual Studio whilst the COM object itself was developed. This meant that I could add functionality to the tests as I added COM functionality to the objects under test. The compiled test could then be checked into source control and run as part of the release build of the object under test. This seemed to work well.

We had a selection of standard COM object tests, the kind of thing that you need to test for all objects. These included things like:

  • Checking for the interfaces that you expect an object to support.

  • Checking that the object didn’t support additional interfaces. This one was harder than the first one. What we did was pull the list of interfaces from HK_CLASSES_ROOT\Interface which was less than ideal but it caught a few problems…

  • Check for the presence of a proxy when you expect one and the lack of a proxy when you don’t expect one. We did this by querying for IProxyManager

  • Check for the presence of the FTM. This was the main reason that I started testing our COM objects, I’d created a new version of an existing object and the new version used the FTM and I needed a way to prove that it actually did (yes, I released a version that said it did but didn’t…) We tested for this by getting the unmarshal class for the object under test and making sure that it was the FTM…

Of course all of these general tests needed to be run in all combinations of across apartment usage. This was the slightly complicated bit. I seem to remember that my COM object test base class dealt with all the threading issues and would create the object under test on the correct kind of thread and then test from the correct kind of thread and do all the permutations that you needed… Doing stuff like that tends to focus the mind on exactly how all that marshalling malarky actually works ;)

Once I was sure that the basic COM stuff was correct for the object I tested each interface. Since we had several common interfaces that many of our objects used I wrote tests for each interface and the object test simply did the basic COM testing and then ran a test for each of the supported interfaces. These were the tests which are most like today’s view of unit tests.

I remember that I used “traits” quite a lot in these tests. This allowed me to pass in a policy which controlled how the test ran. We needed this because the interface test should be usable on all objects that implemented the interface. The traits let us specify things that were per object based; such as the class id that’s returned by a particular instance of IPersistStream etc.

In my opinion this way of testing COM objects was far superior to using a more COM conversant language (like VB) as you could test far more important aspects of the object. I did have to write most of it from scratch though. Later, at another investment bank, some guys had put together a COM version of CPPUnit, but I never really got involved in it… Perhaps Nick Gunn might like to tell us about it?