[rspec-users] Mocking expectations on I/O operations

Andrew Premdas
2011-09-15T21:47:39Z

On 14 September 2011 11:51, Rob Aldred <rob at stardotstar.com>
wrote:
> I''m speccing a small lib which manipulates image files using
mini_magick.
> The lib creates various temporary files during the process, the lib then
cleans up the temporary files at the end.
>
> I''m trying to mock expectations that the calls are made to
File#delete
>
> Eg...
>
File.should_receive(:delete).once.with("#{generator.tmp_path}-full\.png")
>
File.should_receive(:delete).once.with("#{generator.tmp_path}-screen\.png")
>
File.should_receive(:delete).once.with("#{generator.tmp_path}-shadow\.png")
>
> The method in the lib that does this is:
>
> Class IconGenerator
> ...
>
> ?private
>
> ?def cleanup
> ?# remove temporary files created during
> ?# image manipulation
>
?[''-full'',''_screen'',''_shadow'',''_back_shadow''].each
do |f|
> ?File.delete "#{tmp_path}#{f}.png" if File.exists?
"#{tmp_path}#{f}.png"
> ?end
> ?end
> ...
> end
>
> The expectations work fine, however, I also have an after block which also
calls File.delete to clean up the final version of the manipulated test image
>
> after(:each) do
> ?# cleanup manipulated image
> ?File.delete out_dir.join(''MenuIcon.png'') if File.exists?
out_dir.join(''MenuIcon.png'')
> ?end
>
> The File.delete call in the after block fails because its calling the
mocked version of File.delete
> This results in the following error:
>
> Failure/Error: File.delete out_dir.join(''MenuIcon.png'')
if File.exists? out_dir.join(''MenuIcon.png'')
> NoMethodError:
> undefined method `=~'' for
#<Pathname:/Users/robaldred/Sites/egg/tmp/MenuIcon.png>
>
>
> My next step was to stub the write method for every instance of
MiniMagick::Image
> However I will then no longer be able to test the cleanup because the
delete method will never be called if the files don''t exist.
>
> I''m pretty sure I''m going about this the wrong way and
making it difficult for myself here.
> Appreciate any help & feedback
>
> Thanks
> --
> Rob
>
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users
>


Hi Rob,

First of all perhaps you are testing the wrong thing in the wrong place.

As cleanup is a private method, why are you specifying (in this spec
how it works). As far as IconGenerator is concerned currently all you
care about is that it calls cleanup. You''re not interested in how that
cleanup is implemented. If you want to specify how the cleanup works
then make cleanup public - either in this class, or perhaps better yet
in another class. e.g.

describe "Cleanup.clean"
  it "should delete files"
  end
  ...
end

describe IconGenerator
   ...
   it should cleanup
      Cleanup.should_receive(:clean) ...
end

Once you separate the cleanup spec from the IconGenerator spec then
the clash should disappear! You''ll never have to mock File.delete

HTH

Andrew

------------------------
Andrew Premdas
blog.andrew.premdas.org