31

How to test a controller action that sends a file?

If I do it with controller.should_receive(:send_file) test fails with "Missing template" because nothing gets rendered.

Mirko
  • 5,207
  • 2
  • 37
  • 33

4 Answers4

34

From Googling around, it appears that render will also be called at some point .. but with no template, will cause an error.

The solution seems to be to stub it out as well:

controller.stub!(:render)
Andy Lindeman
  • 12,087
  • 4
  • 35
  • 36
26

Another way that works is:

controller.should_receive(:send_file).and_return{controller.render :nothing => true}

To me, this captures the fact that the intended side effect of send_file is to arrange that nothing else be rendered. (Albeit, it admittedly seems a bit wonky to have the stub call a method on the original object.)

Joshua Pinter
  • 45,245
  • 23
  • 243
  • 245
ronen
  • 2,529
  • 26
  • 23
  • 1
    Rails 4, RSpec 3: `'and_return { value }' is deprecated. Use 'and_return(value)' or an implementation block without 'and_return' instead.` – Artem Kalinchuk Sep 01 '15 at 14:26
9

You can also do this:

result = get ....

result.body.should eq IO.binread(path_to_file)
Dave Newton
  • 158,873
  • 26
  • 254
  • 302
Jack Dempsey
  • 2,024
  • 1
  • 16
  • 6
1

This has worked great for me in RSpec controller tests. I prefer to not stub it out, but instead call the original so it does return the file and you can even access the response headers, etc...

expect(controller).to receive(:send_file).with(some_filepath, type: "image/jpg").and_call_original
user2490003
  • 10,706
  • 17
  • 79
  • 155