Reputation: 2800
I want to know whether this solution is community approved by mocking object in ruby. If not please describe why, and how can I improve design of code or maybe test.
Consider I have the following code.
lib/config_loader.rb
class ConfigLoader
HOME_DIR = '~/my/home_dir'.freeze
...
def load(path)
path = File.expand_path(path)
if File.exist?(path)
File.read(path)
else
File.read(HOME_DIR)
end
end
end
When testing I actually do not want anything to be created under path
that I defined in variable, so I just want to mock this behaviour
spec/lib/config_loader_spec.rb
RSpec.describe ConfigLoader do
describe '.load' do
subject { described.class.new.load(path) }
let(:path) { 'path/that/should/exist' }
context 'when path' do
before do
allow(File).to receive(:exist?).with(path).and_return(true)
allow(File).to receive(:read).with(path).and_return('my content')
end
it { expect { subject }.to_not raise_error { Errno::ENOENT }
end
end
end
maybe should I do some class_double
of File
Class. I'm not sure about the way I provided, so I need some info how to do it in common/best-practices way
Upvotes: 0
Views: 249
Reputation: 369420
One of the fundamental tenets of Test-Driven / Behavior-Driven Development/Design is Don't Mock What You Don't Own (coined in the book Growing Object-Oriented Software, Guided by Tests by Steve Freeman and Nat Pryce).
Your example is violating this tenet: you don't own File
, therefore you should not mock it.
Instead, what you could do is create your own abstraction for interacting with the file system, which only has the functionality you are actually requiring. Then you can create two implementations of this abstraction: one that uses Ruby's File
class, and a mock one that does nothing. If you want to get fancy, you can even create one that simulates a file system in memory.
Of course, you have now just pushed the problem around: you now have untested code in your file abstraction implementation. However, ideally, this code should be "almost" trivial. And obviously, you can still have an integration test both for your file abstraction implementation, and also an integration test for ConfigLoader
that uses the real implementation instead of the mock or the simulation.
Here's some further reading if you are interested:
Upvotes: 2