You’ll often hear proponents of test-driven development claim that unit testing is hard and that it forces them to open up their classes’ hidden logic for them to be testable. That might be true to some degree, but more often in my opinion you’ll find that designing your system to be testable also has the nifty side-effect of separating your logic into .. umm logical chunks… and what I really mean here is that your chunks have a tendency to become
BUT that was not what I was going to say, actually – I just wanted to comment on a nifty thing, I recently found out: implementing my own Matcher to use with NMock.
An NMock Matcher is an abstract class, which requires you to implement the following members:
1 2 |
void DescribeTo(TextWriter writer); bool Matches(object o); |
A matcher can be used in the call to With(...) when stubbing or expecting… an example could be setting an expectation that a search function on our user repository will return an empty result… like so:
1 2 3 4 |
Expect.Once.On(userRepository) .Method("SearchByArbitraryString") .With(Is.StringContaining("what I just wrote")) .Will(Return.Value(new List<IUser>())); |
In the example above, Is is a class containing a static method StringContatining, which returns a matcher of a certain type. Now, when the test runs, and NMock needs to decide if an intercepted function call matches the expectation above, it will iterate though the given matchers, and call their Matches function, passing to it the actual argument as object o.
The matcher returned by StringContaining probably contains an implementation of Matches which looks something like this:
1 2 3 4 |
public override bool Matches(object o) { return o is string && ((string)o).Contains(_substring); } |
where _substring was probably set in the ctor of the matcher when it was constructed by the StringContaining function.
Now that leads me to my recent problem: I needed to pull out the actual argument given when the expected function call was performed. In my case the argument was a delegate, which I wanted to pull out, and then invoke it a few times with different arguments.
What I did was this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
public class SnatchArgMatcher<T> : Matcher where T : class { T obj; public T Object { get { return obj; } } public override void DescribeTo(TextWriter writer) { writer.WriteLine(obj == null ? "(null)" : obj.ToString()); } public override bool Matches(object o) { if (!(o is T)) throw new ArgumentException( string.Format("{0} is not of type {1}", o == null ? "(null)" : o.ToString(), typeof (T).Name)); obj = (T)o; return true; } } |
This allows me to set up an expectation like this:
1 2 3 4 |
var snatcher = new SnatchArgMatcher<ForEachFileHandler>(); Expect.Once.On(fileService) .Method("ForEachFile") .With(snatcher); |
Now, after the code has been run, I have access to the delegate passed to the file service through snatcher.Object.
If someone knows a cooler way to do this, please do post a comment below. Until then, I will continue to think that it was actually pretty nifty.