Being Cellfish

Stuff I wished I've found in some blog (and sometimes did)

December, 2009

Change of Address
This blog has moved to blog.cellfish.se.
Posts
  • Being Cellfish

    2009 Advent Calendar December 5th

    • 0 Comments

    Even though the solution created yesterday ensures thread safety when ImportantMethod is used I'm still not satisfied. It might be that I'm paranoid but when ImportantObject is changed in the future we don't really have any guarantee that the future developer remembers to keep things thread safe. For example if we needed to add AnotherImportantMethod to the ImportantObject it is easy to forget to make that new method thread safe too. Also, the ImportantObject now can be considered to violate the single responsibility principle because it does important things and has a lock to do it thread safe.

    So let's try to keep the ImportantObject focused on the important things to do. And instead create a separate object to tie the lock and important object together. I'll call this object a transaction and the first test can look something like this:

    1: public class Given_a_Transaction 2: { 3: class FakeLock : Lock 4: { 5: public bool IsLocked { get; private set; } 6:   7: public FakeLock() 8: { 9: IsLocked = false; 10: } 11:   12: public void Lock() 13: { 14: IsLocked = true; 15: } 16:   17: public void Unlock() 18: { 19: IsLocked = false; 20: } 21: } 22:   23: private Transaction _transaction; 24: private FakeLock _lock; 25:   26: public Given_a_Transaction() 27: { 28: _lock = new FakeLock(); 29: _transaction = new Transaction(_lock); 30: } 31:   32: [Fact] 33: void It_should_take_lock_when_created() 34: { 35: Assert.True(_lock.IsLocked); 36: } 37: }

    And then the implementation would look like this:

    1: public class Transaction 2: { 3: private readonly Lock _lock; 4:   5: public Transaction() : this(new MutexLock()) 6: { 7: 8: } 9:   10: public Transaction(Lock aLock) 11: { 12: _lock = aLock; 13: _lock.Lock(); 14: } 15: }

    Let's add another test tomorrow!

  • Being Cellfish

    2009 Advent Calendar December 4th

    • 0 Comments

    The problem with yesterday's solution is that we're only testing that the lock is taken when ImportantMethod is called. We don't know if the lock is taken before or after the code that is important to protect. So we have to do something about that. We can do that by extracting the important code in to a virtual method our test code can override:

    1: public class ImportantObject 2: { 3: private readonly Lock _lock; 4:   5: public ImportantObject() 6: : this(new MutexLock()) 7: { 8:   9: } 10:   11: public ImportantObject(Lock aLock) 12: { 13: _lock = aLock; 14: } 15:   16: public void ImportantMethod() 17: { 18: _lock.Lock(); 19: DoImportantThings(); 20: _lock.Unlock(); 21: } 22:   23: protected virtual void DoImportantThings() 24: { 25: // Do things. 26: } 27: }

    Now we can actually verify that the lock is taken when we do the important things:

    1: public class Given_an_ImportantObject 2: { 3: class FakeLock : Lock 4: { 5: public bool Locked { get; private set; } 6:   7: public FakeLock() 8: { 9: Locked = false; 10: } 11:   12: public void Lock() 13: { 14: Locked = true; 15: } 16:   17: public void Unlock() 18: { 19: Locked = false; 20: } 21: } 22:   23: class FakeImportantObject : ImportantObject 24: { 25: private FakeLock _fakeLock; 26: public bool LockedWhenDoingImportantThings { get; private set; } 27:   28: public FakeImportantObject(FakeLock fakeLock) : base(fakeLock) 29: { 30: _fakeLock = fakeLock; 31: LockedWhenDoingImportantThings = false; 32: } 33:   34: protected override void DoImportantThings() 35: { 36: LockedWhenDoingImportantThings = _fakeLock.Locked; 37: } 38: } 39:   40: private FakeImportantObject _importantObject; 41: private FakeLock _lock; 42:   43: public Given_an_ImportantObject() 44: { 45: _lock = new FakeLock(); 46: _importantObject = new FakeImportantObject(_lock); 47: } 48:   49: [Fact] 50: void It_should_take_lock_when_ImportantMethod_is_called() 51: { 52: _importantObject.ImportantMethod(); 53: Assert.True(_importantObject.LockedWhenDoingImportantThings); 54: } 55: }
  • Being Cellfish

    2009 Advent Calendar December 3rd

    • 0 Comments

    Let's continue with the same lock interface and MutexLock implementation as yesterday. In order to switch from dependency injection using generics to a classical constructor injection we have to change the important object to something like this:

    1: public class ImportantObject 2: { 3: private readonly Lock _lock; 4:   5: public ImportantObject() : this(new MutexLock()) 6: { 7: 8: } 9:   10: public ImportantObject(Lock aLock) 11: { 12: _lock = aLock; 13: } 14:   15: public void ImportantMethod() 16: { 17: _lock.Lock(); 18: // Do things. 19: _lock.Unlock(); 20: } 21: }

    Which can be tested like this:

    1: public class Given_an_ImportantObject 2: { 3: class FakeLock : Lock 4: { 5: public 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 _importantObject; 24: private FakeLock _lock; 25:   26: public Given_an_ImportantObject() 27: { 28: _lock = new FakeLock(); 29: _importantObject = new ImportantObject(_lock); 30: } 31:   32: [Fact] 33: void It_should_take_lock_when_ImportantMethod_is_called() 34: { 35: _importantObject.ImportantMethod(); 36: Assert.Equal(1, _lock.NumberOfLocks); 37: } 38: }

    However there is still one big problem with this solution. I'll tell you tomorrow.

  • Being Cellfish

    2009 Advent Calendar December 2nd

    • 0 Comments

    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.

  • Being Cellfish

    2009 Advent Calendar December 1st

    • 0 Comments

    One way of adding tests for thread safety is to let the important object handle the locking through two protected members:

    1: public class ImportantObject 2: { 3: private Mutex _lock = new Mutex(); 4:   5: public void ImportantMethod() 6: { 7: Lock(); 8: // Do things. 9: Unlock(); 10: } 11:   12: protected virtual void Lock() 13: { 14: _lock.WaitOne(); 15: } 16:   17: protected virtual void Unlock() 18: { 19: _lock.ReleaseMutex(); 20: } 21: }

    Now we can write a specification that looks like this:

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

    Now we have a test/specification for thread safety! or do we? 

Page 3 of 3 (25 items) 123