July 05, 2003

Untestable


It's easy to write untestable code. It's natural. Most code that we write will be hard to test unless we explicitly think about testing when we write it...

This code is really simple, yet it's untestable. Why?
DateChangeManager.h

class CDateChangeManager  
{
   public :
      class Listener
      {
         public :
 
            virtual void OnDateChange(
               const CTime &oldDate,
               const CTime &newDate) = 0;
   
         protected :

            ~Listener() {}
      };

      CDateChangeManager();

      typedef unsigned long Cookie;

      Cookie RegisterForNotification(
         Listener &listener);

      void UnRegisterForNotification(
         const Cookie &cookie);

      void CheckForChange();

      CTime GetToday() const;

   private :

      CTime m_today;

      typedef std::map Listeners;

      Listeners m_listeners;

      CCriticalSection m_criticalSection;

      // No copies - do not implement
      CDateChangeManager(const CDateChangeManager &rhs);
      CDateChangeManager &operator=(const CDateChangeManager &rhs);
};

DateChangeManager.cpp

CDateChangeManager::CDateChangeManager()
   :   m_today(CTime::GetCurrentTime())
{

}

CDateChangeManager::Cookie CDateChangeManager::RegisterForNotification(
   Listener &listener)
{
   CCriticalSection::Owner lock(m_criticalSection);

   Cookie cookie = reinterpret_cast(&listener);

   m_listeners[cookie] = &listener;

   return cookie;
}

void CDateChangeManager::UnRegisterForNotification(
   const Cookie &cookie)
{
   CCriticalSection::Owner lock(m_criticalSection);

   Listeners::iterator it = m_listeners.find(cookie);

   if (it != m_listeners.end())
   {
      m_listeners.erase(it);
   }
}

CTime CDateChangeManager::GetToday() const 
{
   return m_today;
}

void CDateChangeManager::CheckForChange()
{
   const CTime now = CTime::GetCurrentTime();

   struct tm tmNow;

   now.GetGmtTm(&tmNow);

   struct tm tmToday;

   m_today.GetGmtTm(&tmToday);

   if (tmNow.tm_year != tmToday.tm_year || 
       tmNow.tm_yday != tmToday.tm_yday)
   {
      CCriticalSection::Owner lock(m_criticalSection);

      const CTime then = m_today;

      m_today = now;

      for (Listeners::iterator it = m_listeners.begin(); it != m_listeners.end(); ++it)
      {
         Listener *pListener = it->second;

         if (pListener)
         {
            pListener->OnDateChange(then, now);
         }
      }
   }
}

Share this entry: Email it! | bookmark it! | digg it! | reddit!

Posted by Len at July 5, 2003 12:05 AM | Comments (0) | Categories : Testing
Comments
Post a comment









Remember personal info?




Enter this code in the box below to prove that you're not some kind of automated spam robot...