El 09/07/2010, a las 14:29, Frank J. Mattia escribió: >>> 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. Cheers, Wincent _______________________________________________ rspec-users mailing list rspec-users@rubyforge.org http://rubyforge.org/mailman/listinfo/rspec-users