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