> >>> it "should explicitly set created_by" do > >>> controller.stub(:current_user) { mock_user } > >>> mock_order.should_receive(:created_by=).with(mock_user) > >>> post :create > >>> end > > >>> This is my newly working spec. Does this look well thought out or is > >>> there some glaring pitfall to doing it this way? > > >> Well, this is the way mocking and stubbing works. If you want to set an > >> expectation on an object that doesn't exist yet at the time you're setting > >> up the spec, you have to "chain" things so as to inject a mock of your own > >> at the right place, which you've done here. The amount of work you have to > >> do setting this up will vary from case to case. > > >> This is one of the costs of the interaction-based approached, and you have > >> to weigh up that cost against the benefits. > > > Out of curiosity, how would you do this with a state based approach? > > I've tried checking the value of created_by after post :create but my > > assign(:order) has no idea what :created_by is. > > assigns(:order).created_by.should eq(mock_current_user) just doesn't > > do what I thought it would. > > Ok, some qualifications: > > - I use factories heavily (in this example Factory Girl) to make it easier to > write tests. I don't worry about the slowness of using real model instances > until the spec suite actually becomes large enough for it to be a problem. I > also don't worry about the risk of cascading failures (broken model breaks > controller spec) because I value the simplicity that comes with keeping > mocking and stubbing to a minimum in the specs, and I am wary of the > insulation that mocking and stubbing bring and can actually hide real > failures (eg. API changes but spec keeps passing anyway). I still do mock and > stub, but generally only where it is not easier to just verify state (and it > often is easier). > > - I use RR for mocking because I like the syntax. Even in a state-based > approach, you'll see I have to stub out the "current_user" method on the > controller. > > - I use a "before" block that sets up @user, @params, and does the stubbing, > so that I can reuse the same stuff in many different "it" blocks. > > - And I try to keep each "it" block as short as possible, just do the post > then inspect the state afterwards. In this case the state that I am checking > for is the externally visible stuff like what got assigned (assigns), what > got rendered (render_template) or redirected (redirect_to), what flash or > cookies got set, and so on. If need be, I can query the database. > > - And finally, note that this is written for Rails 3/RSpec 2, which I've been > using solidly for the last month and have now forgotten what Rails 2/RSpec 1 > specs looked like! > > So with all that said, this is more or less what my state-based approach > would look like: > > before do > @user = User.make! > stub(controller).current_user { @user } > @params = { :post => { :title => 'foo', :body => 'bar' } } > end > > it 'should set created_by' do > post :create, @params > assigns[:post].created_by.should == @user > end > > ... > > The controller/action is treated as a "black box" which I never look inside. > Each "it" block basically just follows this pattern: > > 1. Feed params into the black box > 2. Check _one_ piece of state afterwards > > By trying to keep only one "should" assertion in each "it" block I get nice > granularity in the event of failure. > > It is not "better" nor "the right" way, it is just "a" way of doing it. I've > also written controller specs where I ended up mocking left, right and > center, but if I can take the state-based approach I generally prefer it. The > app I'm currently working on has about 3,000 examples, and the suite runs > fast enough that I don't yet feel the need to change my emphasis away from > state-based testing.
Thanks for all your help. I've been toying around with a few different approaches to these two ways and I'm starting to make sense of it all. I too have been using Factory Girl (after spending a day creating my own factory implementation and not knowing what it was). I can't say I'm sold on rr but it does look promising. After trying mocha for all of 32 seconds I just couldn't take it (any_instance made me twitch) and went back to rspec mocking & stubbing... I'll keep it in the back of my mind for a day that I'm feeling experimental. Anyway, thanks again. You've been a huge help. Cheers, - FJM _______________________________________________ rspec-users mailing list rspec-users@rubyforge.org http://rubyforge.org/mailman/listinfo/rspec-users