[rspec-users] How to spec code with multiple (interacting) paths
Ashley Moran
work at ashleymoran.me.uk
Thu Feb 22 10:40:04 EST 2007
On 20 Feb 2007, at 13:05, Jerry West wrote:
> I doubt there is an ideal solution. You might try to encapsulate the
> different behaviours in different classes (each spec'd separately).
> Where there are true alternatives, you could use SimpleDelegator to
> delegate to the appropriate class depending on your flag. No less
> work
> but conceptually cleaner perhaps.
Jerry
One of the times this crops up most is with Rails controllers that
behave differently based on their parameters. So, for example, I'm
writing a credit card form now that behaves differently if there is
a start date or not. Another one was a case when a form action was
receiving 3 models and 3 confirmation checkboxes, and I wanted to
spec the behaviour in the case of each being invalid. I'm not sure I
could really split these up anyway.
> Alternatively (better?) work to eliminate the flag. especially if
> it's a
> do / don't do choice. If you don't need to do something, don't
> call the
> code. Push the decision and hence the spec up a level. The calling
> routine should not do anything if the flag is false. This is the
> boundary case of delegation: there's no need to spec a class that
> doesn't do anything.
I gave a boolean as a simple example. I've wrote other code that
does all sorts of wierd stuff depending on where values lie, so there
are many possible paths. Again, I'm mainly concerned right now with
controllers, so the only layer above is the browser. And if I'm
writing models, the last thing I want to do is push decisions up into
the controller, because it would divide the business logic.
I suppose what I could do with controllers is split out the code that
deals with the parameters, something along the lines of (but better
thought out than) this brain dump:
class ApplicantController < ApplicationController
class SaveDetailsParameterParser
def new(params)
# create models
end
# models
def applicant; end
def address; end
def vehicle; end
def models_valid?; end
end
def save_details
p = SaveDetailsParameterParser.new(params)
redirect_to :action => 'error_page' if !p.models_valid?
end
end
This would be acting like a factory for all objects required by the
action, and could be specified independently. Then I wouldn't need
to check that the controller behaves correctly under 3 different
invalid models, just that if anything is invalid it behaves
correctly. (Pretty much identical to the way you spec the individual
validations in a model, then spec that the controller behaves
correctly if its invalid.)
Maybe you were thinking along these lines? It's hard to put things
across sometimes without writing code out.
Ashley
More information about the rspec-users
mailing list