One of the more complicated Ruby/Rails projects we work with at Highgroove has many points where it interacts directly with the filesystem.
Writing tests for an application whose code requires reading from or writing to the filesystem presents challenges, especially if done naively.
While it’s tempting to simply use the real filesystem during unit tests, this presents a few problems:
So what’s the solution? Fake the filesystem during unit tests.
More after the break.
Consider the following (contrived) piece of code:
Now, what’s the best way to test it? The tests can’t touch /etc/passwd due to permissions, and even if they could, writing to /etc/passwd would be destructive to the system.
How about mocking
This works, but tightly couples the test code. What if someone comes along and refactors the production code, making use of
File.readlines instead of
The code still works, but the test breaks because
File.read is stubbed, not
File.readlines. In fact, it’s now reading from the real system’s /etc/passwd. The code still works, but the test broke. Ugh!
A better solution is to stub the entire filesystem at a higher level, giving a blank slate each time a new test runs. Nothing is ever actually written to the filesystem.
Enter the fakefs gem.
It’s trivial to get up and running. If using bundler, I recommend adding it to the
Next, configure RSpec to include the fakefs helpers to automatically activate and deactivate fakefs whenever a test is tagged with
And finally, write tests that are tagged with
fakefs: true. But this time, test code can manipulate any part of the filesystem, knowing it’s completely emphemeral and isolated:
Voila! While there is a bit more test code, the test is verifying behavior, not the specific implementation. Do you have any other tips for testing code that interacts with the filesystem?