Thread: [Cppunit-devel] hierarchy sample bug...
Brought to you by:
blep
|
From: Baptiste L. <bl...@cl...> - 2001-05-05 21:43:11
|
Well, another stuff to clean up would be that one. There is a well
hidden bug in this sample dealing with hiearchy:
In the template BoardGameTest:
virtual void registerTests(CppUnit::TestSuite *suite)
{
suite->addTest (new CppUnit::TestCaller<BoardGameTest> ("testReset",
&BoardGameTest<GAMECLASS>::testReset));
suite->addTest (new CppUnit::TestCaller<BoardGameTest> ("testReset",
&BoardGameTest<GAMECLASS>::testResetShouldFail));
}
=> BoardGameTest class will be instantiated by each test caller.
and:
class ChessTest : public BoardGameTest<GAMECLASS> {
...
void registerTests(CppUnit::TestSuite *suite)
{
BoardGameTest<GAMECLASS>::registerTests(suite);
suite->addTest (
new CppUnit::TestCaller<ChessTest> ("testNumberOfPieces",
&ChessTest<GAMECLASS>::testNumberOfPieces));
}
=> for ChessTest we have the parent class test caller instantiating
BoardGameTest instead of ChessTest !!!!
The way I found to correct this is to make registerTests() a template member
:-(. This is done in the HelperMacros as follow:
static CppUnit::Test *suite()
__ThisTestCaseType *test =NULL;
CppUnit::TestSuiteBuilder<__ThisTestCaseType> suite;
__ThisTestCaseType::registerTests( suite, test );
return suite.takeSuite();
}
template<class TestCaseType>
static void
registerTests( CppUnit::TestSuiteBuilder<TestCaseType> &suite,
TestCaseType *test )
{
__ThisSuperClassType::registerTests( suite, test )
...
}
At the current time, I haven't found any easier way to to this :-(. Any
ideas ?
Baptiste.
---
Baptiste Lepilleur <gai...@fr...> http://gaiacrtn.free.fr/index.html
Author of The Text Reformatter, a tool for fanfiction readers and writers.
Language: English, French (Well, I'm French).
|
|
From: Bastiaan B. <bas...@li...> - 2001-05-06 00:48:24
|
Baptiste Lepilleur wrote:
> Well, another stuff to clean up would be that one. There is a well
> hidden bug in this sample dealing with hiearchy:
>
> In the template BoardGameTest:
>
> virtual void registerTests(CppUnit::TestSuite *suite)
> {
> suite->addTest (new CppUnit::TestCaller<BoardGameTest> ("testReset",
> &BoardGameTest<GAMECLASS>::testReset));
> suite->addTest (new CppUnit::TestCaller<BoardGameTest> ("testReset",
> &BoardGameTest<GAMECLASS>::testResetShouldFail));
> }
> => BoardGameTest class will be instantiated by each test caller.
>
> and:
> class ChessTest : public BoardGameTest<GAMECLASS> {
> ...
> void registerTests(CppUnit::TestSuite *suite)
> {
> BoardGameTest<GAMECLASS>::registerTests(suite);
> suite->addTest (
> new CppUnit::TestCaller<ChessTest> ("testNumberOfPieces",
> &ChessTest<GAMECLASS>::testNumberOfPieces));
> }
> => for ChessTest we have the parent class test caller instantiating
> BoardGameTest instead of ChessTest !!!!
>
That is correct behaviour. The BoardGameTest checks invariants that should hold
for all BoardGameTest instances, including Chess objects. The testReset()
method in BoardGameTest should equally apply to Chess objects. Overriding
testReset() in ChessTest is a serious indication that the design of application
is flawed.
However, there is one problem, which may be what you hint at: the current
BoardGameTest implementation implies that all BoardGame classes have a default
constructor and need no further setup.
Lemme think this over.
Bye,
Bastiaan
>
> The way I found to correct this is to make registerTests() a template member
> :-(. This is done in the HelperMacros as follow:
>
> static CppUnit::Test *suite()
>
> __ThisTestCaseType *test =NULL;
> CppUnit::TestSuiteBuilder<__ThisTestCaseType> suite;
> __ThisTestCaseType::registerTests( suite, test );
> return suite.takeSuite();
> }
>
> template<class TestCaseType>
> static void
> registerTests( CppUnit::TestSuiteBuilder<TestCaseType> &suite,
> TestCaseType *test )
> {
> __ThisSuperClassType::registerTests( suite, test )
> ...
> }
>
> At the current time, I haven't found any easier way to to this :-(. Any
> ideas ?
>
> Baptiste.
>
> ---
> Baptiste Lepilleur <gai...@fr...> http://gaiacrtn.free.fr/index.html
> Author of The Text Reformatter, a tool for fanfiction readers and writers.
> Language: English, French (Well, I'm French).
>
> _______________________________________________
> Cppunit-devel mailing list
> Cpp...@li...
> http://lists.sourceforge.net/lists/listinfo/cppunit-devel
|
|
From: Baptiste L. <bl...@cl...> - 2001-05-07 08:46:20
|
> Baptiste Lepilleur wrote:
>
> > Well, another stuff to clean up would be that one. There is a well
> > hidden bug in this sample dealing with hiearchy:
> >
> > In the template BoardGameTest:
> >
> > virtual void registerTests(CppUnit::TestSuite *suite)
> > {
> > suite->addTest (new CppUnit::TestCaller<BoardGameTest>
("testReset",
> > &BoardGameTest<GAMECLASS>::testReset));
> > suite->addTest (new CppUnit::TestCaller<BoardGameTest>
("testReset",
> > &BoardGameTest<GAMECLASS>::testResetShouldFail));
> > }
> > => BoardGameTest class will be instantiated by each test caller.
> >
> > and:
> > class ChessTest : public BoardGameTest<GAMECLASS> {
> > ...
> > void registerTests(CppUnit::TestSuite *suite)
> > {
> > BoardGameTest<GAMECLASS>::registerTests(suite);
> > suite->addTest (
> > new CppUnit::TestCaller<ChessTest> ("testNumberOfPieces",
> > &ChessTest<GAMECLASS>::testNumberOfPieces));
> > }
> > => for ChessTest we have the parent class test caller instantiating
> > BoardGameTest instead of ChessTest !!!!
> >
>
> That is correct behaviour. The BoardGameTest checks invariants that should
hold
> for all BoardGameTest instances, including Chess objects. The testReset()
> method in BoardGameTest should equally apply to Chess objects. Overriding
> testReset() in ChessTest is a serious indication that the design of
application
> is flawed.
I agree with that. Though in some case you might have some "template
method" (the pattern) in your test case. I can see that applying when you
have some specific behavior and want to factor some testing part. An example
that pop up into my mind would be testing visitor/strategy/builder. The
setup of each test may be identical and you would want to factor out those
part in a base class. Then, you would use the self-shunt pattern (having the
test case implementing the visitor interface...), and delegate part of the
actual test to the derived test case.
> However, there is one problem, which may be what you hint at: the current
> BoardGameTest implementation implies that all BoardGame classes have a
default
> constructor and need no further setup.
This is indeed the main problem I see. You want the setUp() and
tearOff() method of your derived class to be called: initialization of the
"game" class, initialization of the default database connection for the
current thread...
Baptiste.
---
Baptiste Lepilleur <gai...@fr...> http://gaiacrtn.free.fr/index.html
Author of The Text Reformatter, a tool for fanfiction readers and writers.
Language: English, French (Well, I'm French).
|