Unit tests to validate COM interfaces

Creating a COM server in VFP is easy, maybe too easy. Check the OLEPUBLIC checkbox or add the OLEPUBLIC keyword to the class definition and you are done. Building a DLL creates a COM server that you can pass to anyone who needs to interface with your application. Using a COM server in VFP is similar uneventful. Instantiate the COM server using the ProgId and call methods on the object, that's it.
A COM interface consists of a list of method pointers. Each method is accessed by its index number. When .NET imports a COM server, it internally creates a mapping which forwards any call of a named method to the corresponding index in the interface. As long as the interface doesn't change, life is good. Have an updated version of the COM server? Just copy it over the existing DLL or EXE.

Any interface change, however, requires a lot of work for the .NET developer. The COM server needs to be imported again. The InterOp library must be generated anew. Depending on how the COM server is used by the application, the entire application might need to be recompiled. The old COM server has to be unregistered; the new one to be distributed and registered.

That's quite a bit of work, but manageable if you tell your clients about the modified interface. Unfortunately VFP makes it way too easy to introduce interface changes accidentally.

How does VFP generate the interface for a COM server?

For every COM class, VFP loops through all public properties and methods and assigns id values. The first method or property in the PRG file is id 0, the second PEM becomes id 1, and so forth. In other words, the physical order determines the id value. This index is the same one that early binding languages use to call methods and access properties.

It's probably obvious now that there're at least two ways to alter the COM interface in a way which wouldn't have any impact on Visual FoxPro, at all: If you rearrange methods in your source code, the index numbers change. Secondly, any new property or method that you don't mark protected or hidden, is added to the interface, as well.

At least for me the second one is a major source for headache. Visual FoxPro uses an object based approach to protected members where almost any other OOP language uses a class based approach. This renders protected PEMs in Visual FoxPro basically useless, which is why I often don't bother making procedures protected. I do even less so with properties as protected properties in Visual FoxPro make it hard to debug code properly and therefore affect code quality negatively. But that's food for another controversy discussion..

After refactoring code and accidentally changing the interface, I took a defensive approach to make sure this won't happen again. I added a unit test similar to the following one for every COM class in my project. It doesn't detect changes to the order of PEMs, but it's sufficient to make sure I'm aware of interface changes to the COM server:


Procedure Test_CheckInterface

Local loBO
loBO = CreateObject("MyCOM.Server")
This.AssertTrue( "Error loading MyCOM.Server", ;
Vartype(m.loBO)=="O" )

Local laPem[1]
This.AssertEquals( "Wrong number of PEMs", 4, ;
AMembers(laPem, m.loBO, 3) )
This.AssertEquals( "
1", "Method1", laPem[1,1] )
This.AssertEquals( "
2", "Method2", laPem[2,1] )
This.AssertEquals( "
3", "PEM1", laPem[3,1] )
This.AssertEquals( "
4", "PEM1", laPem[4,1] )

EndProc

For every method there's one item in the array created by AMembers. Properties have two entries, one for the getter, and one for the setter. Since I added this unit tests, I made the same mistake several times. But I always spotted the problem before I even prepared the distribution set.