Well, starting on new stuff functionnalities agin...
TestCaller provides a way to expect macro. Yesterday I try to had a new macro:
CPPUNIT_TEST_EXCEPTION( method, ExceptionType), that would construct a
TestCaller that would expect the specified method to throw an exception.
I remembered the discussion we had about using a decorator to do that. I
tried to create such a thing, but...
What we want to decorate is TestCase::runTest(). Ideally we would create a
ExceptionTestCase class that would decorate a TestCase, and forward setUp(),
tearDown() to that testcase, and implement runTest() by forwarding to the
testcase's runTest(), but expecting it to throw the exception.
The problem is that TestCase is using the TemplateMethod pattern and runTest
() is protected.
So I fell back on the current solution on use the TestCaller to do that. But
that raise the inconsistancy issue between the testcaller (can expect
exception), and the testcase. I also needed to add a template method to
TestSuiteBuilder (with a dummy pointer to pass the exception type).
Notes that I'll probably add another macro:
CPPUNIT_TEST_FAIL( method ), which expand to CPPUNIT_TEST_EXCEPTION( method,
CppUnit::Exception). That one is actually of use when you test testing classes
(you write an utility class that compare some expected and actual data
structure, and is complicated enough that you want to test it).
For short term, I'll report the change using that solution (it's hidden
behind macros) to the CVS tree when the branch is done.
Let's talk about long term...
The core of the problem is that the only way to change the behavior of
TestCase::runTest() is by subclassing.
This go with another issue I have: I want to be able to extend the framework
to to include new recognized exception class in TestCase::run() (for example,
using RogueWave library, you get RWXMsg as a base class instead of
std::exception).
An obvious way to do both would be able to pass a "decorator" to TestCase::run
() that would be used to run the actual testcase:
class TestCaseDecorator
{
public:
virtual setUp( TestCase *test );
virtual runTest( TestCase *test );
virtual tearDown( TestCase *test );
};
TestCase::run( TestResult *result, TestCaseDecorator *decorator )
{
// [...]
try
{
decorator->setUp();
try
{
decorator->runTest();
}
// [...]
decoartor->tearDown();
}
// [...]
}
The decorator would probably not be a paremeter. I could TestResult becoming
something more than just "result", and handling a "stack" of decorator (you
could push a decorator that would decorate all previous decorator).
If we had something like this, we could:
- handle new exception type.
- handle "expected exception" using decorator: subclass Test, and push the
decorator that expect the exception in run(), then call the decorated test run
() method, pop the decorator.
Baptiste.
---
Baptiste Lepilleur <gai...@fr...>
http://gaiacrtn.free.fr/index.html
Language: English, French
|