[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