Imagine we have following piece of code:
class A
def create_server
options = {
name: NameBuilder.new.build_name
}
do_some_operations(options)
end
end
To test such methods, I've used to use allow_any_instance_of
:
it 'does operations' do
allow_any_instance_of(NameBuilder).to receive(:build_name)
# test body
end
But docs advise us not to use it because of several reasons. How then avoid allow_any_instance_of
? I've came to only one solution:
class A
def create_server
options = {
name: builder.build_name
}
do_some_operations
end
private
def builder
NameBuilder.new
end
end
But with such approach code quickly becomes full of almost useless methods (especially when you actively using composition of different objects in described class).
If it is difficult to test, it means you have a problem in your class design. In your case, when you are doing testing for specific method call on a specific class within a class you are testing like this:
allow_any_instance_of(NameBuilder).to receive(:build_name)
Your test know exactly how the method is implemented internally. Your classes should encapsulate the logic and hide it. You are doing exactly the opposite.
You should not be testing any internal method logic. Just test the behaviour. Give inputs and test the correctness of the output.
If you really want to test that method call on NameBuilder
class, then inject that dependency and make your class more testable. This also follows OOP principles.
class A
def create_server(builder)
do_some_operations(name: builder.build_name)
end
end