I‘m working on making a legacy code base more testable and made good progress with (constructor)-injecting dependencies to classes.
I noticed something in all classes that access the file system: they make calls to C#’s static helper classes like System.IO.File
or System.IO.Directory
. To really be able to unit test these classes I need to mock the calls to those methods as well.
Is this a common practice? I would write an interface like IFileAbstraction
which could e.g. include the method definition void WriteAllText(string path, string content)
which would then be implemented by a Mock object during unit-testing. During normal execution, I imagine a class that just routes the calls to the corresponding helper class (in this case System.IO.File#WriteAllText(string path, string content)
.
Is there a better way to achieve testability of file-system accessing classes?
Small note: I use Autofac
as a DI container, so it is pretty easy to handle mutiple injected dependencies in my refactored classes.
1
You should not start to mock out IO because you think you need to follow religiously some some unit testing dogma found in some book. You mock them out when you notice some real issues with the IO code in your tests, which could be
-
your tests become so slow that you cannot run them as frequently as you would like to
-
you cannot easily make the original IO code access the specific files and folders with your test data
So the only “best practice” here is not stick to some cargo cult, but write the test which needs to be written, regardless whether it is a unit test in the strict sense or not.
Assumed you notice one of the above issues, the approach scetched in your question is fine, though the details may differ depending on how many IO methods need to be called, if they depend on each other, if they just read data or create data and folder structures. If only performance is an issue, and you can choose the storage location freely and don’t need much persisted test data, you may also consider to use some Ram based file system for testing.
Recommended read: The Way of Testivus – Less Unit Testing Dogma – More Unit Testing Karma
You don’t mock the calls to static library methods, that would defeat the purpose of the test. You inject file system paths to known locations with known content so you can tell whether you file processing went according to plan.
7