Mixin Base Classes

Introduction

Occasionally, you have some invariant that you want to maintain, and you want to check that many of your tests, in different suites, maintain that invariant. One technique that can help with this is to write a class whose only job is to help you check that invariant, and to have the tests in question inherit from that class.

These sorts of mixin base classes typically reset the environment somehow in their constructor, and check the environment in their destructor, calling FAIL() if the invariant in question isn't preserved. They probably also provide some helper functions to allow tests to query the environment while running.

Your test may also inherit from some other base class (e.g. one doing common setup/teardown for the suite containing it); if so, it's usually a good idea to inherit from the mixin class first, so its constructor runs first and its destructor runs last.

We provide one sample mixin base class: ExistingBase.

ExistingBase

The class ExistingBase is useful when you're testing a class that manages other objects (e.g. a smart pointer class or a collection class), and you want to make sure that the managed objects are being created and destroyed at appropriate times. It lets you keep a count of the objects in question, and check to make sure that appropriate numbers of objects exist at all times.

To use it, you should include unittest/ExistingBase.hpp. This provides two class templates: ExistingObject<> and ExistingBase<>. If you tests are using a class called, say, Managed for the objects under management, then you should have Managed inherit from ExistingObject<Managed>. This will modify Managed's constructors and destructor to keep a count of the number of live objects at any given time.

Next, your tests should inherit from ExistingBase<Managed>. This provides two pieces of functionality. The first is that it has a member function, existing(), which returns the number of live objects. You can use this in your test to check that objects are being created and destroyed at appropriate times; for example, when testing a smart pointer class, you might check that the number of objects that exist is 1 before the smart pointer goes out of scope and 0 afterwards. The second piece of functionality is that the destructor checks to make sure that there are no objects left at the end of the test, and fails the test otherwise. This gives an easy way to guard against object leaks.


david carlton <carlton@bactrian.org>