How to isolate Directory.Exists in unit testing using disposable pattern
Earlier i wrote a blog post about isolating DateTime.Now with disposable pattern. Here is a little more advance example for the static method Directory.Exists.
So here is the simple example of product code that we want to test
public void ProcessFiles(string path) { if (!DirectoryIsolator.Exists(path)) { throw new ArgumentException("Path doesn't exist"); } } |
This first test method is simple setting the return value to false before calling the product code
[TestMethod()] [ExpectedException(typeof(ArgumentException))] public void Class1_ProcessFiles_SettingReturnValueFalse() { using (DirectoryIsolator.ExistsIs(false)) { Class1 target = new Class1(); string path = @"C:\windows"; target.ProcessFiles(path); } } |
This second test case is using delegated to get the same result. The power with using delegates is that you can fine tune the response to-do exact what you want and record any additional information that you want to test.
[TestMethod()] [ExpectedException(typeof(ArgumentException))] public void Class1_ProcessFiles_SettingDelegateToReturnFalse() { using (DirectoryIsolator.ExistsIs(delegate(string s) { return false; })) { Class1 target = new Class1(); string path = @"C:\windows"; target.ProcessFiles(path); } } |
And final the implementation of the Directory isolator. As we all know unit test should not have any side effect and always leave machine as found. That is here achieved by using a IDisposable pattern. In this way the original functionality of DirectoryIsolator is automatic reverted back after tested.
public class DirectoryIsolator : IDisposable { enum ExistsAction { PassTrought, ReturnValue, Function } private static bool existsReturnValue; private static Func<string, bool> existsReturnFuction; private static existsAction existsaction = ExistsAction.PassTrought; public static bool Exists(string path) { switch (existsaction) { case ExistsAction.ReturnValue: return existsReturnValue; case ExistsAction.Function: return existsReturnFuction(path); } return Directory.Exists(path); } public static IDisposable ExistsIs(bool value) { existsReturnValue = value; existsaction = ExistsAction.ReturnValue; return new DirectoryIsolator(); } public static IDisposable ExistsIs(Func<string, bool> function) { existsaction = ExistsAction.Function; existsReturnFuction = function; return new DirectoryIsolator(); } public void Dispose() { existsaction = ExistsAction.PassTrought; } } |
All of this could have been done by moles for example or by changing the API so it would be possible to inject different behavior into the code. But I prefer to make my code testable strait out of box with as few changes to the public API as possible, since it will make my code more robust.
Link to to code: StaticClassIsolators
Comments
One Response to “How to isolate Directory.Exists in unit testing using disposable pattern”Trackbacks
Check out what others are saying about this post...[…] Bron : Peter Wibeck’s blog Lees meer… […]