Loading ...
Sorry, an error occurred while loading the content.

118823Re: [XP] Re: TDD and C++

Expand Messages
  • Philippe AMELINE
    Apr 8, 2006
      David Carlton a écrit :

      >On Sat, 08 Apr 2006 16:50:04 +0200, Philippe AMELINE <philippe.ameline@...> said:
      >
      >
      >>David Carlton a écrit :
      >>
      >>
      >
      >[ advantages for using constructor/destructor in place of
      >setUp/tearDown deleted ]
      >
      >[ other miscellaneous comments deleted ]
      >
      >
      >
      >>This point really seems of interest, but the way you describe it is
      >>too technical to be plainly understandable for me... and probably
      >>for some others ;-)
      >>
      >>
      >
      >
      >
      >>Can you illustrate what you say by some simple examples... or point
      >>out some references?
      >>
      >>
      >
      >I'm happy to talk about this at length - just tell me what you want me
      >to talk about. Do you want me to talk about the advantages of doing
      >things in the way I recommend, how to implement it, or something else?
      >
      >If the implementation is the question, here's a sketch of how I
      >refactored from the old way of doing things to the new way of doing
      >things.
      >
      >WARNING: I am typing this code off of the top of my head; I would be
      >shocked if I didn't make a typo somewhere. I hope the ideas are
      >there, though.
      >
      >In the old version, I had classes like this:
      >
      > class Test {
      > public:
      > virtual void setUp() {}
      >
      > virtual void run() = 0;
      >
      > virtual void tearDown() = 0;
      > };
      >
      > class Suite : public Test {
      > public:
      > void run(); // sets up, runs, tears down all tests in list
      >
      > void addTest(Test *test); // adds a test to the list
      >
      > private:
      > std::list<Test *> tests_;
      > };
      >
      >
      >This might be used as follows:
      >
      > class StackBase : public Test {
      > public:
      > void setUp() { stack_ = new Stack(); }
      >
      > void tearDown() { delete stack_; }
      >
      > protected:
      > Stack &stack() { return *stack_; }
      >
      > private:
      > Stack *stack_;
      > };
      >
      > class PushPop : public StackBase {
      > public:
      > void run() {
      > ASSERT(stack().empty());
      >
      > stack().push(1);
      >
      > ASSERT(!stack().empy());
      > ASSERT_EQUAL(1, stack().pop());
      >
      > ASSERT(stack().empty());
      > }
      > };
      >
      > // Other stack tests go here.
      >
      > class StackSuite : public Suite {
      > public:
      > void setUp() {
      > newTest(new PushPop())
      > // Add other stack tests here.
      > }
      > };
      >
      >
      >Which is fine (and we did things this way for maybe a couple of
      >years), but it has its limitations. For example, if the individual
      >tests want to add more setup/teardown functionality, it's easy to
      >forget to call the base class's setup/teardown, or to call it in the
      >wrong place.
      >
      >So we added the following:
      >
      > template<typename T>
      > class TestHolder : public Test {
      > public
      > void setUp() { test_ = new T(); }
      >
      > void run() { test_->run(); }
      >
      > void tearDown() { delete test_; }
      > };
      >
      >And we added another addTest() method to Suite:
      >
      > class Suite {
      > public:
      > // Rest as above.
      >
      > template<typename T>
      > void addTest() {
      > addTest(new TestHolder<T>);
      > }
      > };
      >
      >Then our earlier StackBase example turns into this:
      >
      > class StackBase {
      > protected:
      > Stack &stack() { return stack_; }
      >
      > private:
      > Stack stack_;
      > };
      >
      >No need for explicit setUp/tearDown at all: the compiler generated
      >default constructor/destructor do our job for us. (It's also not
      >unusual for setUp to be replaced by a short constructor that we have
      >to write, and for tearDown to vanish.)
      >
      >And StackSuite just does
      >
      > addTest<PushPop>();
      >
      >instead of
      >
      > addTest(new PushPop());
      >
      >Which is no harder (or easier) than the other version.
      >
      >
      >Is this useful? Please tell me areas where you'd like elaboration
      >(either here or in my earlier e-mail), and I'll be happy to say more.
      >
      >
      Thank you David,

      From what I understand, the main advantage is to have the setup
      function incorporated in the constructor and the tear down function in
      the destructor.
      Then the object has just to be created and deleted at the proper time.

      You are also making use of templates to make this behavior generic.

      Nice use of C++ capabilities.
      Can you share the base code, so we can play with it (and maybe collaborate)?

      Philippe
    • Show all 27 messages in this topic