berkes
berkes

Reputation: 27563

Mock a `puts` to a file in Rspec

I have a silly "queue-class[1]" with the following method, that I want to spec out with Rspec. I am not interested in testing if writing to the file-system works (It works, my computer works) but in whether or not the correct data gets written away.

def write transaction
  File.open("messages/#{@next_id}", "w") {|f| f.puts transaction }
  @next_id += 1
end

The spec for testing this is:

describe TransactionQueue do
  context "#write" do
    it "should write positive values" do
      open_file = mock File
      open_file.stub(:puts)

      File.any_instance.stub(:open).and_yield(open_file)
      File.any_instance.should_receive(:open)
      open_file.should_receive(:puts).with("+100")

      @queue = TransactionQueue.new
      @queue.write("+100")
    end
  end
end

Running this, fails, because my Mocks never receive the expected "open" and "puts" messages.

Can I mock File this way? Did I use the any_instance correctly; is my attempt to stub a "block-yield" correct?

I'd rather not use extra gems like FakeFS when it can be avoided; this is not so much about getting it to work; bu mostly about actually understanding what is going on. Hence my attempt to avoid extra gems/layers of complexity.

[1] Class is from The Cucumber Book; but these tests have littel to do with Cucumber itself. I somehow broke the code when following the book; and want to find out what, by writing unit-tests for the parts that the book does not write tests for: the helper classes.

Upvotes: 3

Views: 1867

Answers (1)

Thomas
Thomas

Reputation: 181785

It's not "any instance" of the File class that you expect to receive the open method; it's the File class itself:

  File.stub(:open).and_yield(open_file)
  File.should_receive(:open)

Furthermore, don't use both a stub and an expectation. If you want to verify that File.open is actually called:

  File.should_receive(:open).and_yield(open_file)

If you merely want to stub the open method in case it gets called, but don't want to require it as behaviour of the @queue.write method:

  File.stub(:open).and_yield(open_file)

(This is from memory, I haven't used RSpec for a few months.)

Upvotes: 6

Related Questions