On Thu, Mar 27, 2014 at 3:48 AM, Matthew Riley
[email protected] wrote:
Of the two examples below, which do you believe is more testable?
Example 1:
class Car
def initialise(engine)
@engine = engine
end
…
Example 2:
class Car
def initialise
@engine = Engine.new
end
Definitely #1, as it will accept any sort of engine-like thing you
care to put in it, so you can use a mock or stub or other kind of
fake, even without relying on a faking library to monkey with the item
(or worse yet, with Engine).
I might be tempted to make a slight change, though: declare the
initializer as “def initialise(engine = Engine.new)”, so you don’t
have to explicitly pass in an Engine in the default case. Yes, that
re-couples them somewhat, that’s the downside. If you can be sure
that Car always has access to Engine, like if they’re all part of the
same gem you’re distributing, this is probably acceptable. In fact,
you could do something like:
def initalize(options={})
@engine = options[:engine] || Engine.new
@transmission = options[:transmission] || Transmission.new
@horn = options[:horn] || Horn.new
and so on
end
or if you want to really delve into funky Ruby, maybe even do some
metaprogramming to DRY up that pattern, like:
def initalize(options={})
[:engine, :transmission, :horn].each do |sym|
option = options[sym]
klazz = Kernel.const_get(sym.capitalize)
self.instance_variable_set(sym, option || klazz.new)
end
end
That might be more worthwhile if you have a long list of options to pass
in.
-Dave
–
Dave A., freelance software developer (details @ www.Codosaur.us);
see also www.PullRequestRoulette.com, Blog.Codosaur.us, www.Dare2XL.com