Re: [Cppunit-devel] class overview I: defining tests
Brought to you by:
blep
From: Steve M. R. <ste...@vi...> - 2001-07-11 14:42:38
|
Hi, Baptiste: thanks for your comments; they are helping clarify the CppUnit design in my mind. Everyone: other comments welcome! On Tue, Jul 10, 2001 at 03:24:45PM +0200, Baptiste Lepilleur wrote: > Quoting "Steve M. Robbins" <ste...@vi...>: > > > class Test > > ---------- > > > > CppUnit has a small hierarchy of classes rooted at class Test. Test > > is a pure virtual class with no implementation code. I will assume it > > is intended to be an interface class. By this I mean it exists only > > to define the interface that a "test-like" classes must implement. If > > we were writing Java, it would be an interface. > > Just to put it out since we haven't yet, Test/TestCase/TestSuite are > respectively the Component/Leaf/Composite of a Composite pattern. Thanks! That's a useful pointer. > > The Test interface has one principal method: > > > > void run( TestResult* res ) > > - run the test and collect the results in res > > Don't dismiss getName(), it is an essential element of "reporting" result. True. While writing, I was in the mind frame of someone who wanted to understand "how do I write a test case for my code". The method getName() should have appeared in part II, but I think I forgot to mention it there, too. > > class TestCase > > -------------- > > > > The concrete class that represents a test should be TestCase. > > In fact, however, TestCase is a framework to define one OR MORE tests. > > The detailed description of TestCase says it defines the "fixture > > to run multiple tests". > > > > The term "fixture" is bothering me. The documentation suggests that a > > TestCase _is_ a fixture. If so, why have two terms? Does the word > > "fixture" have a standardized meaning? > > > > TestCase is a subclass of Test, and implements run() as > > > > setUp() > > runTest() > > tearDown() > > > > According to the "cookbook", a TestCase object is intended as the > > basic mechanism for defining a test. One should subclass TestCase > > overriding runTest() appropriately. The code in runTest() would > > typically make a number of assertions. > > I'm not sure what "fixture" means in english. The dictionnary did not provide > anything that made sense. The "running" definition I have is that a fixture > provides "context" and "facility" to run a test. I do not know of any > standardized meaning, though it's also used in JUnit if I remember well. OK. I have not looked at JUnit. Does anyone know whether JUnit originated the term, or whether it has an antecedent? I think the term is being used, as you suggest, as a synonym for "framework", except that it is "smaller" than a framework or a sub-part of a framework. Something like: "fixture" is to "framework" as "test case" is to "test suite"? > > class TestCaller > > ---------------- > > > > Here is where I really start getting muddled. > > > > A TestCaller is a subclass of TestCase that "provides access to a test > > case method". Although nowhere clarified in the docs, "a test case > > method" appears to refer to any member function of a TestCase that > > takes no parameters and returns void. > > > > All through the TestCaller documentation, the term "fixture" is > > used to mean "a TestCase instance". > > > > As near as I can tell, a TestCaller exists so that one can subclass a > > TestCase, define a number of "void foo(void)" methods in it, and then > > use a TestCaller to make an individual test case out of each such > > method. > > > > I'm confused now as to whether an object of type TestCase should > > be a single test case or a set of related test cases. The name > > suggests it is a single test case. However, the TestCaller class > > appears to promote the practice of defining a set of related tests > > in a TestCase, and then generating a test case (TestCaller) for each. > > I finally get why you are so confused. Indeed you pointed out a weird stuff > in the design. > > To write a unit test, you basically have two ways: > - subclass TestCase, and override the runTest() method to implement your test. > - have a class that define a setUp() and a tearOff() methods, and some tests > methods. Then create a TestCaller to create a TestCase for each test method. > > As you can see, TestCaller does not really need a TestCase. As to why > TestCase is used, you'll have to go down to the original CppUnit version. > The fact are (concerning the use of TestCase to create test suite of > TestCaller): > - TestCase provides a base class, which define setUp() and tearOff() with > empty implementation. > - TestCase defines extraneous methods, such as getName(), runTest()... > - TestCase is not use as a TestCase. > > Having a base class is a good thing (At least I think so, it make writing the > macros much easier). > Having the extraneous methods and a "wrong" use of TestCase is confusing. > > To solve that problem, I would suggest introducing a new base class: [ ... TestFixture ... ] Yes, I think this would clarify the design. To reiterate, TestFixture would contain setUp() and tearDown() methods. [You keep using "tearOff", but I assume you really mean "tearDown", yes?] You would subclass this, define void methods, and use the latter as a parameter to TestCaller to create test cases. With TestFixture, it seems that TestCase may be defined as class TestCase : public Test, public TestFixture and supply implementations of the Test methods, like run(). > Hope this help solve the confusing stuff. (Note that JUnit is even weirder in > that aspect). Oh dear! Maybe I *shouldn't* have a look at JUnit after all. I'm already confused enough :-/ > > In addition, the TestCaller class is able to ignore an "expected" > > exception in its runTest() method. This is a useful facility! > > Why is it not available in the base TestCase class? > > It is more than "ignoring": if the expected exception is not caught, the test > failed. This means that we are implementing a test. True. I was being sloppy in my description. > I believe the base TestCase class should remain "test free" (provide facility > to run and report result, but to not do any test). But you rise an interesting > question: should the "exception" expected test be in a TestDecorator rather > than in TestCaller ? This would also make the TestCaller "test free". Whatever the mechanism, it just seems to me that a test case defined 1. by subclassing TestCase, or 2. by subclassing TestFixture and invoking TestCaller ought to have the same facilities, including testing for "expected exceptions". If you mean to make a new TestDecorator subclass for expecting exceptions, akin to the existing RepeatedTest, then yes; to me, that sounds like the way to procede. It has the added virtue of simpler code in the common case, when the proposed decorator is NOT used. > > classes TestDecorator, RepeatedTest, TestSetUp > > ---------------------------------------------- > > > > TestDecorator and RepeatedTest are straightforward. > > > > TestSetUp is a mystery, though. It appears very similar to > > the TestCase class in that it wraps the Test::run() method > > with virtual setUp() and tearDown() methods. But it doesn't > > do any catching of exceptions like TestCase does. > > What is the purpose of this class? > To use delegation instead of subclassing to set a testing context. > > Here is an example of use: > Problem: I need to set a global context each time I run the tests using the > TestRunner. This could be initializing Thread Local Storage to set up the > Database connexion, initializing resource such as COM... > Solution: I provide a way for the user to "wrap" the test being run. The user > could use TestSetUp to do that. I'm not sure I understand. Is the set up code to be run once at the beginning of a test run? Or is it to be run just before each individual test case? Do you have a real-life example use of TestSetUp that shows why it is superior to other means (subclassing?) of achieving the same end? -Steve -- by Rocket to the Moon, by Airplane to the Rocket, by Taxi to the Airport, by Frontdoor to the Taxi, by throwing back the blanket and laying down the legs ... - They Might Be Giants |