On Nov 21, 2007 10:22 AM, Chris Olsen <[EMAIL PROTECTED]> wrote: > As for views I fail to see why testing it with a mock model does > anything. Nothing is ensuring that when changes are made to the model > that they will also be done to the mocks then causing the test to break. > If anything, having the false security when all tests pass is worse, in > that it may prevent you from double checking something crucial.
Keep in mind that testing is about design, rather than testing. When your specs are all green, it means that your code is in a more-or-less stable state, not that it's correct. Rails encourages you to do funky stuff like user.company.sites.build params[:site] That's going to be a PITA to write a spec for. In my experience, if something is hard to spec, it's probably not the best design. Compare describe SitesController, " POST /companies/acme/sites" do include UserSpecHelpers before(:each) do login_as mock_user @mock_company = mock_model(Company) Company.stub!(:find_by_nickname).and_return @mock_company mock_user.stub!(:company).and_return @mock_company @sites_proxy = mock("sites proxy") @mock_company.stub!(:sites).and_return @sites_proxy @mock_site = mock_model(Site) @sites_proxy.stub!(:build).and_return @mock_site end def do_post post :create, :company_id => "acme", :site => {"name" => "foo"} end it "should find the company" do Company.should_receive(:find_by_nickname).with("acme").and_return @mock_company do_post end # assume that we do something like found_company == user.company # implicitly checking call because we've stubbed all the associations it "should build a site" do @sites_proxy.should_receive(:build).with("name" => "foo").and_return @mock_site do_post end it "should save the site" do @mock_site.should_receive(:save).and_return true do_post end end to describe SitesController " POST /companies/acme/sites" do include UserSpecHelpers before(:each) do login_as mock_user @mock_company = mock_model(Company, :add_site => true) Company.stub!(:find_by_nickname).and_return @mock_company mock_user.stub!(:access_company?).and_return true Site.stub!(:new).and_return :mock_site end def do_post post :create, :company_id => "acme", :site => {"name" => "foo"} end it "should find the company" do Company.should_receive(:find_by_nickname).with("acme").and_return @mock_company do_post end it "should see if the user has access to the company" do @mock_user.should_receive(:access_company?).with(@mock_company).and_return true do_post end it "should create a site" do Site.should_receive(:new).with("name" => "foo").and_return :mock_site do_post end it "should add the site to the company" do @mock_company.should_receive(:add_site).with(:mock_site).and_return true do_post end end The first one works, but it's ugly. We have to do a lot of setup, and then the specs just aren't very expressive. The controller is going to be coupled to the low-level model structure, and we didn't really do anything to help ourselves. The second one is much, much nicer. First of all, there's less setup, and the setup that's there is much more clear. We're just stubbing out some methods, rather than hooking up a bunch of relationships. The specs themselves are actually valuable. They read well, and, assuming that we wrote the spec and controller before the underlying model, they helped us discover a nice API. I think that #access_company? and #add_site will prove to be quite useful. It's really easy to fall into the trap of writing controller code that would lead to the first spec I showed. I even wrote those kinds of specs when I first started! I was thinking too much about what I "knew" to be the final implementation, rather than focusing on just writing the specs in a fluid, natural way, guiding me towards the final implementation. Eventually after writing all those ugly, painful specs you realize that there's probably a better way, and you come on this list asking for help. People offer alternative approaches and hopefully it snaps. > I think tests for views makes sense when there is a condition that must > be tested, ex. if a new member must fill in additional fields that are > made visible only when they are from a certain country. A test may then > make sense to ensure that the fields exist. I didn't do view specs for the longest time. Recently though I've learned that they are important. I have a bad habit of working hard to make the controller and model clean and well-designed, and then just jamming a bunch of stuff in the view. I mean, it's just the view, right? There's not a lot going on, and the designers are supposed to deal with that stuff anyway. As it turns out, it's incredibly easy to write trainwreck code in the view too! So writing view specs helps you avoid that, again. Just like controller specs, view specs will help guide you to push more things down into the model. Also, I think the combo of view + controller specs help you make design decisions like when to refactor to a Presenter. For example, you've got a controller which pulls a couple things out of an order object - the user, shipping address, billing address, and the line items. As your app grows, you might end up with 5 or 6 specs, where you have to stub out all of that stuff. You could refactor the specs themselves, writing little helper methods to hook all of that up for you. Or you could refactor the production code so you do something like "@presenter = OrderPresenter.new(order)". Then you can replace those 5 slightly different specs with one generic spec that uses a Presenter, and let the Presenter handle any details. I've done this several times, and I don't think I'd arrive at that solution if I didn't use the test style that I do. There are no hard-and-fast rules, but as a general rule, I find that if something is hard to spec then it's probably not a great design. Ultimately good design is about being able to easily use your code, and change it when needed. Thorough testing, using mocks, helps you first by defining how your code will be used, and second by pointing out sources of pain when you try to make changes. Pat _______________________________________________ rspec-users mailing list rspec-users@rubyforge.org http://rubyforge.org/mailman/listinfo/rspec-users