Timer – Part 2

2 12 2010

Finally, Timers and all that Jazz. Let’s continue with a quick sneak peek into the previous post and the original requirements.

Another thing I would like to test is whether our timer is running or not.

TEST_FIXTURE(timer_not_running, _check_timer_is_not_running)
{
  CHECK_EQUAL(false, _timer.IsRunning());
}

Add the functionality and remove the duplication.

#ifndef _TDD_TIMER_
#define _TDD_TIMER_

class Timer
{
  public:
    typedef char* name_type;
    typedef double elapsed_type;

    bool IsRunning() const { return _isRunning; }
    name_type Name() const { return _name; }
    elapsed_type TotalElapsed() const { return _totalElapsed; }

    Timer(name_type name)
    : _name(name)
    , _totalElapsed(0)
    , _isRunning(false)
    {}

  private:
    bool _isRunning;
    name_type _name;
    elapsed_type _totalElapsed;
};

#endif/*_TDD_TIMER_*/

Compile, run, works, let’s stop for a moment and think. At the end of the last post I’ve had to make a design decision regarding the Timer and with the boolean test I’ve just written that decision comes into light. But what is it? The answer lies in the fixture itself. By allowing tests to be carried across a Timer object which is not running I’ve actually also stated that the Timer object will have to be started manually by the class users. It may seem to be a small part of the overall design and probably fairly intuitive and/or obvious but we also have to remember that this functionality emerged as a consequence of writing the tests first. Another benefit of these tests which can become apparent is their value as documentation. With just a glance at the name of this fixture we are already shown what can and needs to be done in order to use our Timer.

There’s one last thing I can think of that the Timer needs at the moment and that’s the ability to measure the time elapsed between updates. A timer that hasn’t been started and hasn’t updated should report that value as zero though.

TEST_FIXTURE(timer_not_running, _check_tick_elapsed_is_zero)
{
  CHECK_EQUAL(0, _timer.TickElapsed());
}

And we know the drill by now so let’s just skip and create the property and variable in the same step.

#ifndef _TDD_TIMER_
#define _TDD_TIMER_

class Timer
{
  public:
    typedef char* name_type;
    typedef double elapsed_type;

    bool IsRunning() const { return _isRunning; }    
    name_type Name() const { return _name; }    
    elapsed_type TickElapsed() const { return _tickElapsed; }    
    elapsed_type TotalElapsed() const { return _totalElapsed; }

    Timer(name_type name)
    : _isRunning(false)
    , _name(name)
    , _tickElapsed(0)
    , _totalElapsed(0)
    {}

  private:
    bool _isRunning;
    name_type _name;
    elapsed_type _tickElapsed;
    elapsed_type _totalElapsed;
};

#endif/*_TDD_TIMER_*/

Run the tests, see that everything works. And that’s all the functionality I can think of that our non-running timer should or can expose for us. We need to step it up, go crazy… Let’s make a timer that actually runs!

#include <UnitTests.h>
#include "Timer.h"

struct timer_is_running
{
  Timer::name_type _name;
  Timer _timer;

 ~timer_is_running(){}
   timer_is_running()
   : _name("IsRunning")
   , _timer(_name)
   {}
};

TEST_FIXTURE(timer_is_running, _check_timer_name_is_correct)
{
  CHECK_EQUAL(_name, _timer.Name());
}

Run tests and everything is green. Now comes a little confession. I’m not sure whether I should re-test the name functionality which is immutable in the sense that the name cannot change and has already been proven to be working properly by removing the code duplication from the previous tests. For now I’ll keep the test and the test-code duplication it [sort of] brings, why? I’m not sure…

Let’s look at the running timer concept. I know that the fixture as it stands will not start a timer running because the previous test for IsRunning() passes on false. My assumption though is that the IsRunning() on a running timer should be true. Test time.

TEST_FIXTURE(timer_running, _check_is_running)
{
  CHECK_EQUAL(true, _timer.IsRunning());
}

Run and fail. Clearly we need a way to start the timer and change the value returned by IsRunning(). Unlike the previous tests I can’t just hardcode a return true since the other test will fail. I’ve got to actually add a function to do that and call it before I test, to do this I’ll modify the fixture a bit.

#include <UnitTests.h>
#include "Timer.h"

struct timer_is_running
{
  Timer::name_type _name;
  Timer _timer;

 ~timer_is_running(){}
   timer_is_running()
   : _name("IsRunning")
   , _timer(_name)
   {
      _timer.Start();
   }
};

Compile, run… Hey, it’s not even compiling now; apparently we need to actually write the Start() function.

#ifndef _TDD_TIMER_
#define _TDD_TIMER_

#include <cassert>

class Timer
{
  public:
    typedef char* name_type;
    typedef double elapsed_type;

    bool IsRunning() const { return _isRunning; }    
    name_type Name() const { return _name; }    
    elapsed_type TickElapsed() const { return _tickElapsed; }    
    elapsed_type TotalElapsed() const { return _totalElapsed; }

    void Start();

    Timer(name_type name)
    : _isRunning(false)
    , _name(name)
    , _tickElapsed(0)
    , _totalElapsed(0)
    {}

  private:
    bool _isRunning;
    name_type _name;
    elapsed_type _tickElapsed;
    elapsed_type _totalElapsed;
};

inline void Timer::Start()
{
  assert(_isRunning==false);
  _isRunning=true;
}

#endif/*_TDD_TIMER_*/

I’ve jumped a step in there by already putting in the code to change the _isRunning variable because there’s no point in trying to run the tests for running’s sake. I’ve also added an assert there [I’ll assume anyone who reads this also read my other posts about preconditions/postconditions and writing custom asserts]. The assert is another preliminary test to communicate the internal logic of the Timer. In this case I’ve chosen to say that trying to Start a running timer is cause for alarm because somewhere there’s a logic misstep. Anyway, compile, run, test and pass.

This post is running a bit long and I’m running a bit tired but I’m happy with the direction this is taking…

“I pounded on a farmhouse looking for a place to stay, I was mighty mighty tired I had come a long long way”

Advertisements

Actions

Information

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s




%d bloggers like this: