Share via


2009 Advent Calendar December 2nd

Adding virtual methods to handle locks as we did yesterday is really not a good solution. The lock should be a separate object and in order to be able to fake the lock I'll make it an interface:

    1:      public interface Lock
   2:      {
   3:          void Lock();
   4:          void Unlock();
   5:      }
   6:   
   7:      public class MutexLock : Lock
   8:      {
   9:          private readonly Mutex _lock = new Mutex();
  10:   
  11:          public void Lock()
  12:          {
  13:              _lock.WaitOne();
  14:          }
  15:   
  16:          public void Unlock()
  17:          {
  18:              _lock.ReleaseMutex();
  19:          }
  20:      }

Considering that it would be pretty neat to inject the lock dependency to the important object using generics:

    1:      public class ImportantObject<Tlock> where Tlock : Lock,new()
   2:      {
   3:          private readonly Tlock _lock = new Tlock();
   4:   
   5:          public void ImportantMethod()
   6:          {
   7:              _lock.Lock();
   8:              // Do things.
   9:              _lock.Unlock();
  10:          }
  11:      }

Then thread safety can be tested like this:

    1:      public class Given_an_ImportantObject
   2:      {
   3:          class FakeLock : Lock
   4:          {
   5:              public static int NumberOfLocks { get; private set; }
   6:   
   7:              public FakeLock()
   8:              {
   9:                  NumberOfLocks = 0;
  10:              }
  11:   
  12:              public void Lock()
  13:              {
  14:                  ++NumberOfLocks;
  15:              }
  16:   
  17:              public void Unlock()
  18:              {
  19:   
  20:              }
  21:          }
  22:   
  23:          private ImportantObject<FakeLock> _importantObject = new ImportantObject<FakeLock>();
  24:   
  25:          [Fact]
  26:          void It_should_take_lock_when_ImportantMethod_is_called()
  27:          {
  28:              _importantObject.ImportantMethod();
  29:              Assert.Equal(1, FakeLock.NumberOfLocks);
  30:          }
  31:      }

However since generics are used we need a static spy in the faked lock which might be a problem if several tests run concurrently. Not typical for unit test runners but not impossible. We'll have to address that later.