On Mon, Jun 16, 2008 at 10:23 PM, Andrew S. [email protected] wrote:
David,
Valid point about the method needing some refactoring. But another key rule
of refactoring is to have passing tests before refactoring.
Catch 22 indeed. Are you familiar w/ Michael Feathers’ book Working
Effectively with Legacy Code? The working definition of Legacy Code in
that book is any code without tests. He’s got a bunch of strategies in
there for dealing with situations like this - not in Rails, but the
same general concepts and trade-offs apply.
Following that book’s advice, you might use integrate_views and create
an example that is more like a Rails functional test to start. Maybe
even an integration test (using RSpec Stories or Rails Integration
Test direction). Then, as you refactor pieces out you can drive that
process w/ smaller examples.
This is one of the things that’s a minor annoyance I have about rails, you
can’t associate views with models. The problem with the refactoring
suggested is that render_to_string is a member of ActionController::Base,
and moving it in to a string construction method in the model is complicated
by no helpers available in the model, and that partial uses tons of helpers.
So it’s hard to move a generate_marker method to the model.
Got it. I wonder if it would be justifiable in a case like this to
create a special object for this purpose then - one that includes all
the helpers you need. Just a thought. Unusual to do that sort of
thing in Rails, but I used to see and do that sort of thing all the
time in other frameworks. Makes things nicely decoupled and easier to
test.
Regardless of all of the above, RSpec controller specs have issues when
testing which template was rendered if you use render_to_string.
I don’t think this is an RSpec problem at all. We’d have the same
problem in any other framework. I’d say it’s a conflict between Rails
design choices and the desire to test at this level of granularity.
Not saying either is “right.” We get a lot of good from both things.
But they are sometimes in conflict.
I’d try testing this at the higher level (as suggested above) to start.
The other thing you might try is mocking render_to_string directly on
the controller.
controller.should_receive(:render_to_string).with(…).any_number_of_times
Or you could stub do_search and return a known set of props to get
more specific, but to do that you’re going to end up with a ton of
mocks and stubs for this example and without anything higher level to
begin with that’s not always the safest bet. But all of this is
temporary.
I think we can agree that the goal is trim this puppy down somehow, so
whatever you do to get there with confidence is OK and throwing out
most of that in favor of more granular examples and methods as they
emerge is definitely OK.
Good luck.
Cheers,
David