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

    The 2009 Advent Calendar Wrap Up

    • 0 Comments

    So I hope I showed you a way to BDD/TDD a thread safe solution without slow pesky tests that needs a number of helper threads to verify thread safety. Also, you're not guaranteed that your code is thread safe just because of your tests when you use threads to try and break your code. You can use something like Chess to find such bugs but having tests that consistently verifies thread safety is much better IMHO.

    And did we create better code this way (because BDD/TDD is about writing better code, right)? I think the separation of concerns between the ImportantObject, ImportantProvider and the Transaction are pretty neat. The introduction of MutexWrapper might be questionable for some people but it illustrates how different concerns should be separated and by doing so you can test more things in a simple way.

    For your convenience here is a summary of all links and the final version of the code.

  • Being Cellfish

    2009 Advent Calendar December 24th

    • 0 Comments

    As I mentioned yesterday we now don't have any tests for the MutexWrapper which is a thin wrapper for the Mutex implementation in .Net. I don't think it is necessary to always have tests for these thin wrappers but sometimes it is a good idea to add a few tests just to verify that you've understood how the API works. These tests should not be run all the time as all your other unit tests but should be part of your acceptance test suite or something similar. Keep them and run them from time to time. This is how it might look for the MutexWrapper:

    1: public class MutexWrapper 2: { 3: private readonly Mutex _lock = new Mutex(); 4:   5: public virtual void WaitOne() 6: { 7: _lock.WaitOne(); 8: } 9:   10: public virtual void ReleaseMutex() 11: { 12: _lock.ReleaseMutex(); 13: } 14: } 15:   16: public class Given_an_unlocked_MutexWrapper 17: { 18: private MutexWrapper _lock = new MutexWrapper(); 19:   20: [Fact(Timeout = 1000)] 21: void It_should_be_possible_to_WaitOne() 22: { 23: _lock.WaitOne(); 24: } 25: } 26:   27: public class Given_a_locked_MutexWrapper : IDisposable 28: { 29: private MutexWrapper _lock = new MutexWrapper(); 30: private Thread _thread; 31: private bool _gotLock = false; 32:   33: public Given_a_locked_MutexWrapper() 34: { 35: _thread = new Thread(() => 36: { 37: _lock.WaitOne(); 38: _gotLock = true; 39: _lock.ReleaseMutex(); 40: }); 41: } 42:   43: public void Dispose() 44: { 45: if (_thread != null) 46: { 47: _thread.Abort(); 48: } 49: } 50:   51: private void CompleteSetup() 52: { 53: _lock.WaitOne(); 54: _thread.Start(); 55: Assert.False(_thread.Join(250)); 56: } 57:   58: [Fact(Timeout = 1000)] 59: void It_should_block_on_WaitOne() 60: { 61: CompleteSetup(); 62: Assert.False(_gotLock); 63: } 64:   65: [Fact(Timeout = 1000)] 66: void It_should_complete_WaitOne_once_released() 67: { 68: CompleteSetup(); 69: _lock.ReleaseMutex(); 70: Assert.True(_thread.Join(500)); 71: Assert.True(_gotLock); 72: } 73: } 74:   75: public class Given_an_abandoned_MutexWrapper : IDisposable 76: { 77: private MutexWrapper _lock = new MutexWrapper(); 78: private EventWaitHandle _threadStarted = new EventWaitHandle(false, EventResetMode.ManualReset); 79: private EventWaitHandle _threadStop = new EventWaitHandle(false, EventResetMode.ManualReset); 80: private Thread _thread; 81:   82: public Given_an_abandoned_MutexWrapper() 83: { 84: _thread = new Thread(() => 85: { 86: _lock.WaitOne(); 87: _threadStarted.Set(); 88: _threadStop.WaitOne(); 89: }); 90: _thread.Start(); 91: } 92:   93: public void Dispose() 94: { 95: if (_thread != null) 96: { 97: _thread.Abort(); 98: } 99: } 100:   101: [Fact(Timeout = 1000)] 102: void It_should_throw_exception_when_waited_for() 103: { 104: _threadStarted.WaitOne(); 105: _threadStop.Set(); 106: Assert.Throws<AbandonedMutexException>(() => { _lock.WaitOne(); }); 107: } 108: }
  • Being Cellfish

    2009 Advent Calendar December 23rd

    • 0 Comments

    And the last test refactored to remove the slow tests:

    1: public class Given_a_locked_MutexLock 2: { 3: private class FakeMutexWrapper : MutexWrapper 4: { 5: public bool Locked { get; private set; } 6:   7: public static int NumberOfLocks { get; private set; } 8: public static int NumberOfUnlocks { get; private set; } 9:   10: public static void Reset() 11: { 12: NumberOfLocks = 0; 13: NumberOfUnlocks = 0; 14: } 15:   16: public FakeMutexWrapper() 17: { 18: Locked = false; 19: } 20:   21: public override void WaitOne() 22: { 23: if (!Locked) 24: { 25: Locked = true; 26: ++NumberOfLocks; 27: } 28: } 29:   30: public override void ReleaseMutex() 31: { 32: Locked = false; 33: ++NumberOfUnlocks; 34: } 35: } 36:   37: private MutexLock<FakeMutexWrapper> _lock = new MutexLock<FakeMutexWrapper>(); 38: 39: public Given_a_locked_MutexLock() 40: { 41: _lock.Lock(); 42: FakeMutexWrapper.Reset(); 43: } 44:   45: [Fact] 46: void It_should_not_take_the_lock() 47: { 48: _lock.Lock(); 49: Assert.Equal(0, FakeMutexWrapper.NumberOfLocks); 50: } 51:   52: [Fact] 53: void It_should_take_lock_when_released() 54: { 55: _lock.Unlock(); 56: _lock.Lock(); 57: Assert.Equal(1, FakeMutexWrapper.NumberOfLocks); 58: } 59: }

    So great! We now have fast test. But... Once again we're not testing the MutexWrapper. We'll take a look at that tomorrow.

  • Being Cellfish

    2009 Advent Calendar December 22nd

    • 0 Comments

    And today we refactor yet another test that is potentially slow when failing (because of the timeout):

    1: public class Given_an_unlocked_MutexLock 2: { 3: private class MutexWrapperAlwaysUnlocked : MutexWrapper 4: { 5: public static int NumberOfLocks { get; set; } 6:   7: public override void WaitOne() 8: { 9: ++NumberOfLocks; 10: } 11:   12: public override void ReleaseMutex() 13: { 14:   15: } 16: } 17:   18: private MutexLock<MutexWrapperAlwaysUnlocked> _lock = new MutexLock<MutexWrapperAlwaysUnlocked>(); 19:   20: public Given_an_unlocked_MutexLock() 21: { 22: MutexWrapperAlwaysUnlocked.NumberOfLocks = 0; 23: } 24:   25: [Fact] 26: void It_should_be_possible_to_lock() 27: { 28: _lock.Lock(); 29: Assert.Equal(1, MutexWrapperAlwaysUnlocked.NumberOfLocks); 30: } 31: }
  • Being Cellfish

    2009 Advent Calendar December 21st

    • 0 Comments

    The change we did yesterday makes it possible to remove the use of helper threads and timeouts for the MutexLock tests. Here is a first refactoring:

    1: public class Given_an_abandoned_lock 2: { 3: private class MutexWrapperAlwaysAbandoned : MutexWrapper 4: { 5: public new void WaitOne() 6: { 7: throw new AbandonedMutexException(); 8: } 9: } 10:   11: private MutexLock<MutexWrapperAlwaysAbandoned> _lock; 12: 13: public Given_an_abandoned_lock() 14: { 15: _lock = new MutexLock<MutexWrapperAlwaysAbandoned>(); 16: } 17:   18: [Fact] 19: void It_should_be_possible_to_take_lock_when_thread_dies() 20: { 21: Assert.DoesNotThrow(() => { _lock.Lock(); }); 22: } 23: }
  • Being Cellfish

    2009 Advent Calendar December 20th

    • 0 Comments

    But wait! What happened yesterday? We added some significant functionality; hiding the fact that AbandonedMutexException might be thrown. Because of this I want to break out the Mutex implementation into a separate, thin wrapper for the Mutex object:

    1: public class MutexWrapper 2: { 3: private readonly Mutex _lock = new Mutex(); 4:   5: public void WaitOne() 6: { 7: _lock.WaitOne(); 8: } 9:   10: public void ReleaseMutex() 11: { 12: _lock.ReleaseMutex(); 13: } 14: }

    Given that I use generics to inject the dependency:

    1: public class MutexLock<T> : Lock where T : MutexWrapper, new() 2: { 3: private readonly T _lock = new T(); 4:   5: public void Lock() 6: { 7: try 8: { 9: _lock.WaitOne(); 10: } 11: catch (AbandonedMutexException) { } 12: } 13:   14: public void Unlock() 15: { 16: _lock.ReleaseMutex(); 17: } 18: }

    I'll spare you the changes needed to make the tests compile for now since the use of MutexWrapper makes it possible to remove all those helper threads and slow tests for the MutexLock class.

  • Being Cellfish

    2009 Advent Calendar December 19th

    • 2 Comments

    So far so good but there is one more thing I want the MutexLock to do. The Mutex object may throw an exception (AbandonedMutexException) when being waited for if the current owning thread terminates without releasing the mutex. I want to hide that fact in my MutexLock so I don't need to handle that exception everywhere in my code:

    1: public class Given_an_abandoned_lock : IDisposable 2: { 3: private MutexLock _lock = new MutexLock(); 4: private EventWaitHandle _threadStarted = new EventWaitHandle(false, EventResetMode.ManualReset); 5: private EventWaitHandle _threadStop = new EventWaitHandle(false, EventResetMode.ManualReset); 6: private Thread _thread; 7:   8: public Given_an_abandoned_lock() 9: { 10: _thread = new Thread(() => 11: { 12: _lock.Lock(); 13: _threadStarted.Set(); 14: _threadStop.WaitOne(); 15: }); 16: _thread.Start(); 17: } 18:   19: public void Dispose() 20: { 21: if (_thread != null) 22: { 23: _thread.Abort(); 24: } 25: } 26:   27: [Fact(Timeout=1000)] 28: void It_should_be_possible_to_take_lock_when_thread_dies() 29: { 30: _threadStarted.WaitOne(); 31: _threadStop.Set(); 32: Assert.DoesNotThrow(() => { _lock.Lock(); }); 33: } 34: }

    And that test leads to the following implementation:

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

    2009 Advent Calendar December 18th

    • 0 Comments

    Yet another passing test to make sure our MutexLock works as expected:

    1: public class Given_a_locked_MutexLock : IDisposable 2: { 3: private MutexLock _lock = new MutexLock(); 4: private Thread _thread; 5: private bool _gotLock = false; 6:   7: public Given_a_locked_MutexLock() 8: { 9: _thread = new Thread(() => 10: { 11: _lock.Lock(); 12: _gotLock = true; 13: _lock.Unlock(); 14: }); 15: } 16:   17: public void Dispose() 18: { 19: if (_thread != null) 20: { 21: _thread.Abort(); 22: } 23: } 24:   25: private void TakeLockAndStartThread() 26: { 27: _lock.Lock(); 28: _thread.Start(); 29: } 30:   31: [Fact(Timeout = 1000)] 32: void It_should_not_take_the_lock() 33: { 34: TakeLockAndStartThread(); 35: Assert.False(_thread.Join(250)); 36: Assert.False(_gotLock); 37: } 38:   39: [Fact(Timeout = 1000)] 40: void It_should_take_lock_when_released() 41: { 42: TakeLockAndStartThread(); 43: Assert.False(_thread.Join(250)); 44: _lock.Unlock(); 45: Assert.True(_thread.Join(500)); 46: Assert.True(_gotLock); 47: } 48: }

    Note that I moved taking the lock from the constructor to a common helper method. This has to do with how xUnit.net runner creates objects and runs tests together with a timeout. Turns out that the object is created in one thread and then the test method is run in a separate thread if a timeout is used. In theory, if everything works as expected I don't really need the timeout but it is very nice to have it just in case the code doesn't work as expected.

  • Being Cellfish

    2009 Advent Calendar December 17th

    • 0 Comments

    Since we already have an implementation for the MutexLock I want to add another passing test:

    1: public class Given_a_locked_MutexLock : IDisposable 2: { 3: private MutexLock _lock = new MutexLock(); 4: private Thread _thread; 5: private bool _gotLock = false; 6:   7: public Given_a_locked_MutexLock() 8: { 9: _lock.Lock(); 10: _thread = new Thread(() => 11: { 12: _lock.Lock(); 13: _gotLock = true; 14: _lock.Unlock(); 15: }); 16: _thread.Start(); 17: 18: } 19:   20: public void Dispose() 21: { 22: if (_thread != null) 23: { 24: _thread.Abort(); 25: } 26: } 27:   28: [Fact(Timeout = 1000)] 29: void It_should_not_take_the_lock() 30: { 31: Assert.False(_thread.Join(250)); 32: Assert.False(_gotLock); 33: } 34: }

    It's starting to get tricky using helper threads but let's continue tomorrow... 

  • Being Cellfish

    2009 Advent Calendar December 16th

    • 0 Comments

    So far I'm pretty pleased with how the ImportantObject is protected by the ImportantProvider but we're dealing with thread safety and how can we be sure the MutexLock class really does what it is supposed to do? We should put that class under its own set of tests. So let's start with a simple one:

    1: public class Given_an_unlocked_MutexLock 2: { 3: private MutexLock _lock = new MutexLock(); 4:   5: [Fact(Timeout=1000)] 6: void It_should_be_possible_to_lock() 7: { 8: _lock.Lock(); 9: } 10: }

    With implementation:

    1: public class MutexLock : Lock 2: { 3: private readonly Mutex _lock = new Mutex(); 4:   5: public void Lock() 6: { 7: _lock.WaitOne(); 8: } 9:   10: public void Unlock() 11: { 12: _lock.ReleaseMutex(); 13: } 14: }
Page 1 of 3 (25 items) 123