2009 Advent Calendar December 24th
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: }