This post is really meant as a follow up to a post made back in March/
April which is now closed:
http://groups.google.com/group/googletestframework/browse_thread/thread/e0123ea04c873283?tvc=2
I have implemented automated memory leak checking in my test fixtures
by using the _Crt* debugging functions provided in Windows. A base
test fixture class checks the state of memory in the SetUp() method,
and then in TearDown(), if HasFailure() returns false, the current
state of memory is compared with the state captured during SetUp() to
check for leaks (using _CrtMemCheckpoint and _CrtMemDifference).
On Fri, Aug 7, 2009 at 12:16 PM, Justin Holzer<jsho...@gmail.com> wrote:
>
> This post is really meant as a follow up to a post made back in March/
> April which is now closed:
> http://groups.google.com/group/googletestframework/browse_thread/thread/e0123ea04c873283?tvc=2
>
> I have implemented automated memory leak checking in my test fixtures
> by using the _Crt* debugging functions provided in Windows. A base
> test fixture class checks the state of memory in the SetUp() method,
> and then in TearDown(), if HasFailure() returns false, the current
> state of memory is compared with the state captured during SetUp() to
> check for leaks (using _CrtMemCheckpoint and _CrtMemDifference).
>
> This method works well except in some cases when the test fixture,
> which is a derived/child class of the base test fixture class, uses
> local member variables to provide common objects for all tests within
> the fixture. For instance, the state of a local member variable may
> change between SetUp() and TearDown(), and when TearDown() is called,
> the test fixture's local data has not yet been cleaned up as the
> destructor has not yet been called. This can trick the _Crt* functions
> in to thinking that there are memory leaks because of the differences
> in memory state between what was captured during SetUp() and TearDown
> ().
>
> One solution to this issue was to move the code in the base class from
> SetUp() into a default constructor, and from TearDown() into a virtual
> destructor.
Sounds good.
Or, you can put the leak checking logic into a separate class (say,
LeakChecker) which does the work in its ctor and dtor. Then you can
add a member variable of type LeakChecker to your test fixture class.
> This way, the initial memory state will be captured prior
> to the child class initializing it's local member variables (since the
> base class constructor is always called first), and the child test
> fixture will be able to clean up it's local member data prior to the
> final memory state being checked (since the base class destructor will
> be called after the child class destructor). This solution does have
> one caveat though.If a memory leak is detected, I would want to be
> able to mark the test as failed (using the FAIL macro). I do not know
> of any way to alter the outcome of the test once the destructor has
> been reached.
Just use FAIL, ADD_FAILURE, or any other assertion macro to cause a
failure.
> In addition, once the base class destructor is reached,
> the child class has been cleaned up already.
This shouldn't be a problem. The test result is not stored in the
test fixture object, so you can generate new failures in the dtor of
the test fixture (or its base class).
> Obviously, the FAIL macro cannot be used in the destructor since it
> returns a value.
This is due to a pecularity of C++. The workaround is simple.
Instead of:
virtual ~Foo() {
...
FAIL(); // Doesn't compile.
...
}
write:
void Destruct() {
...
FAIL();
...
}
virtual ~Foo() { Destruct(); }
For those curious, FAIL() can be used in a void-returning function
only (for some technical reasons), and C++ doesn't consider ctors and
dtors as void-returning functions.
This is documented in
http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide#Assertion_Placement.
Once the event listener API is implemented, you should be able to
register a listener that does the leak checking when a test
starts/ends. The benefit of this approach is that all TESTs and
TEST_Fs in your program are automatically checked - you don't have to
modify them to inherit from a leak checking base test fixture class.
However, since both Vlad and I are on vacation now, it will be a while
before this API can be finished.
--
Zhanyong
I have posted the code for a test fixture base class that will perform
memory leak checking in the constructor and destructor. It can be
found here:
http://dev.opaquepixel.com/code/LeakCheckingTestFixture.h
Thanks for sharing your solution! I'm sure it will help other people.
On Mon, Aug 10, 2009 at 7:41 AM, Justin Holzer<jsho...@gmail.com> wrote:
>
>
> I have posted the code for a test fixture base class that will perform
> memory leak checking in the constructor and destructor. It can be
> found here:
>
> http://dev.opaquepixel.com/code/LeakCheckingTestFixture.h
Some quick comments:
- For maximum reusability, it's better to define the leak checker as a
stand-alone class (not derived from testing::Test). If someone
wants leak checking for a test case, he just needs to add an
instance of the leak checker as a data member of his test fixture
class, instead of inheriting from LeakCheckingTestFixture. This
allows different enhancements to be easily combined in the same
fixture. (Suppose someone else develops another enchancement also
as a subclass of testing::Test (say, BarFixture), you cannot derive
your fixture from both LeakCheckingTestFixture and BarFixture, as
both classes share the same, duplicated base class testing::Test.
In contrast, you can easily use both enhancements in the same
fixture if they aren't subclasses of testing::Test.)
- You can replace the call to failTest(...) with ADD_FAILURE() << ....
Then you don't need the failTest() function.
--
Zhanyong
On Mon, Aug 10, 2009 at 7:57 PM, Jay Sprenkle<jspr...@gmail.com> wrote:
>
>>
>> I have posted the code for a test fixture base class that will perform
>> memory leak checking in the constructor and destructor. It can be
>> found here:
>>
>> http://dev.opaquepixel.com/code/LeakCheckingTestFixture.h
>
> Hey Justin,
> I did some poking around and found the gnu malloc system includes a call to
> determine how much memory is currently allocated. The following is able to
> find failures in both malloc and new, at least with my trivial testing:
>
> #include <malloc.h>
>
> /**
> * A base GTest (GoogleTest) text fixture class that supports memory leak
> checking.
> *
> * NOTE: when using this class as a base class for a test fixture,
> * the derived class should not create any local member variables, as
> * they can cause memory leaks to be improperly reported.
> */
> class BaseTestFixture : public ::testing::Test
It's better to define this as a stand-alone class (i.e. not a subclass
of testing::Test), as I pointed out in my reply to Justin.
> {
> public:
> virtual void SetUp()
It's better to do the leak checking in the ctor/dtor as opposed to
SetUp/TearDown:
- It can catch leaks caused in the ctor/dtor of a fixture derived from
BaseTestFixture.
- When the user needs to define his own SetUp/TearDown in a derived
fixture class, he doesn't need to remember to call SetUp/TearDown in
BaseTestFixture.
--
Zhanyong
> Zhanyong,
>
> If the class that provides the memory leak checking did not extend
> testing::Test, would the FAIL macro still work properly? I would think
> the answer would be yes, but I haven't had the chance to try it yet.
The answer is yes.
http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide#Assertion_Placement
says:
"You can include assertions in any C++ function's code. The one
constraint is that assertions that generate a fatal failure (FAIL* and
ASSERT_*) can only be used by void-returning functions."
Perhaps we should make it more obvious that by "any" we mean the
funciton doesn't have to be a member of the test fixture class.
> Also, wouldn't it also work to just define the leak checking class as
> an additional base class of the test fixture?
>
> For instance:
> class MyTestFixture : public testing::Test, public LeakChecker
>
> Or perhaps there could still be a base test class that would have the
> same signature as above and test fixtures could just extend it:
> class LeakCheckingTest : public testing::Test, public LeakChecker
> {};
> class MyTestFixture :: public LeakCheckingTest {};
>
> I see the point about portability, in that a class that is doing
> memory leak checking certainly has applications outside of test cases.
This is a good point, but not the same one I was making. I was saying
that a test fixture class may want to use both leak checking and some
other utility. This wouldn't be possible if both leak checking and
the other utility are implemented as subclasses of testing::Test.
> I just don't feel comfortable about declaring a member variable to
> provide the memory leak checking. I guess I just always felt that
> inheritance was the "proper" way in OOD to inject additional
> functionality in to a class hierarchy, though I suppose it's really a
> matter of personal preference.
Not entirely. Inheritance is for the "is-a" relationship, while
composition is for the "uses" relationship. In this case, the test
fixtures *uses* a leak checker, but itself is not a leak checker.
Therefore it's more appropriate to make the leak checker a member
variable.
For more info on why implementation inheritance and multi-inheritance
are suspicious, you can read
http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Inheritance
> I will try a minor refactoring with a separate LeakChecker class and
> see how that goes. Thanks for all the great feedback.
>
> - Justin
--
Zhanyong
No. You just need to declare the LeakChecker object as the *first*
member variable of the fixture class. C++ guarantees that it's
constructed before and destructed after other member variables.
> The memory
> leak checking needs to be done prior the initialization of test
> fixture member variables, and after their destruction, and the only
> way I know of that will do this is by using the ctor/dtor of a base
> class.
>
> So you might end up with something like...
>
> class BaseTestFixture : public testing::Test
> {
> public:
> virtual BaseTestFixture()
> {
> leakChecker.Start(); // have the LeakChecker capture initial
> memory state
> }
>
> virtual ~MyTestFixture()
> {
> leakChecker.Finish(); // tell the leak checker to compare current
> mem state with the initial one
>
> if (leakChecker.FoundLeaks())
> failTest("Memory leak detected!");
> }
>
> private:
> void failTest(const char* message)
> {
> FAIL() << message;
> }
>
> LeakChecker leakChecker;
> };
This wouldn't be necessary.
> Down the road, if I needed additional features in my test cases, I
> could either enhance the BaseTestFixture class or create a new
> subclass that my test fixtures requring the added functionality could
> themselves inherit from. Am I still missing the point here?
If you have N enhancements, how many combinations do you want to
provide? You'd end up with 2 to the power of N variations, which is
infeasible. It's best to define the N enhancements separately and
allow them to be freely combined by the user.
--
Zhanyong