Now here is basically the same code after the transform I described in my last posting. I've added a template parameter to deal with the globals and I've even made it so that the system type HWND can be changed to something simple so you don't need windows.h

And now I include this very cheesy Mock version of the template which shows where you could put your test hooks. Note that the OS types HWND and HANDLE are no longer present. This code is OS neutral. LPSECURITY_ATTRIBUTES could have been abstracted as well but I left it in because I'm lazy. Note that HANDLE and HWND are now just int. This mock could have as many validation hooks as you like.

In your test code you include calls that look like this to run your tests. You could easily put this into whatever unit test framework you have.

void DoWhateverMock(int hwnd){ DoWhateverHelper<Mock, int>(hwnd);}

And that's it.

It wouldn't have been much different if we had used an abstract class instead of a template to do the job. That can be easier/better, especially if the additional virtual call isn't going to cost you much.

We've boiled away as many types as we wanted to and we kept the heart of the algorithm so the unit testing is still valid.

Actually we can do better still in boiling away the types: I forgot about typename. If we do this

template <class T> void DoWhateverHelper(typename T::HWND hwnd)

Then we can have

struct Mock

{

typedef int HWND;

…

}

and

struct Normal

{

typedef ::HWND HWND;

}

And we can add more, boiling away LPSECURITY_ATTRIBUTES with ease. Although this is a case where the code isn't even using LPSECURITY_ATTRIBUTES so it would have been easiest to do this in Normal

struct Normal

{

…

static HANDLE CreateMutex(BOOL fOwn, LPCWSTR args)

{

return ::CreateMutex(NULL, fOwn, args);

}

…

}

Note that all we did with the return of CreateMutex was store it but if there was more complex logic we might have needed T::HANDLE just like T::HWND and we could treat it the same, boiling away the windows dependency.