How to Test for File Operations with FakeFS and RSpec

Background:

Say you have controller method that creates and writes into a file and you’d like to be able to run expectations on the behavior and not so much of the implementation.

The normal way would be to do something like:

def test_creates_directory
  FileUtils.expects(:mkdir).with("directory").once
  Library.add "directory"
end

because this just doesn’t work.

def test_creates_directory
  Library.add "directory"
  assert File.directory?("directory")
end

So one way to solve this is with this gem called FakeFS. The code snippet above, is taken from their documentation.

FakeFS stubs your Filesystem and allows you to perform expectations by interacting directly with files that were created without actually creating and messing up your actual Rails.root.

Lets start:

Step 1: Setup the Gem

  # Gemfile
  gem "fakefs", :require => "fakefs/safe"

Step 2: Activate FakeFS in the tests that requires it

In your /spec_file, include the various helpers:

# /spec/model/your_spec.rb

require 'fakefs/spec_helpers'

describe YourModel do
  include FakeFS::SpecsHelper
end

Step 3: Write your tests!

# /spec/model/your_spec.rb

require 'fakefs/spec_helpers'

describe YourModel do
  include FakeFS::SpecsHelper

  it "should return a file with its content having a line length of 140 characters" do
    # This is like the first safety check. Run this before your File Operations
    FakeFS.activate!

    # This is something special, it will take a while to load everytime you run
    # the test, so don't panic if you're wondering why it appears that the test
    # is "stuck". This stubs your existing Filesystem.
    FakeFS::FileSystem.clone(Rails.root)

    file = generate_file_and_return_filename("magic_happens_here")

    File.readlines(file).each do |line|
      expect(line.length).to eq(141)
    end

    FakeFS.deactivate!
  end
end

And you’re done! Now you have a perfectly stubbable Filesystem, which doesn’t actually create and save the file into your actual Rails Environment.

Cheers!