On Mon, Jan 4, 2010 at 5:26 AM, Ijonas Kisselbach < ijonas.kisselb...@gmail.com> wrote:
> Hi David, > > I see your point about concentrating on outcomes rather than > implementation. I suppose who cares about implementation, its the effect > code on the "state of the world" that is important. > > Here's an unmodified sample: > context ", when a new policy is activated on unchanged content" do > before(:each) do > setup_common_mocks > end > > it "should create a new policy, the new violation and location, resolve > previous violations, recalculate location MD5, and refresh caches" do > # content hasn't changed > @content = mock(:content, :content_md5 => "84290324908230948", > :most_recent_violations => [mock(:violation_mr, :update_folder_count => > nil)]) > @content_descriptor = mock(:content_descriptor, :contents => > [...@content], :most_recent_content => @content, :folder => mock(:folder)) > > ContentDescriptor.should_receive(:by_path_md5_and_site).once.and_return([...@content_descriptor]) > > > # Policy is new, gets created once > Policy.should_receive(:find_by_account_category_and_name).once > > PolicyCategory.should_receive(:find_by_account_and_name).once.and_return(mock(:policy_category)) > Policy.should_receive(:create!).once.and_return(mock(:policy)) > > # below are the changes affected > Violation.should_receive(:resolve_violations).once > > Violation.should_receive(:recalculate_violation_md5).once.and_return(10) > > Violation.should_receive(:find_by_content_id_and_policy_id).once.and_return(nil) > violation = mock(:new_violation1, :location_md5= => nil, :save => > true) > Violation.should_receive(:new).once.and_return(violation) > violation.should_receive(:save).once > > Location.should_receive(:create!).once.and_return(mock(:location1)) > > @content.should_receive(:most_recent_violations=).once > @content.should_receive(:unresolved_violation_count=).once > @content.should_receive(:save).once > CacheMaintenance.should_receive(:remove_folder_cache_keys).twice > record > end > > end > > I'm going to try and refactor the specs so that anything that doesn't > directly modify state of the app is removed. > Why are you mocking so much here? Why not set up the db in a known state, invoke the action you want to invoke (record???) and set expectations about the outcomes? If you're concerned about database access and speed, this is a case where I think the benefits of just invoking the code outweighs the cost of database access. I'm imagining something more like this: context ", when a new policy is activated on unchanged content" do it "creates a new policy" do record # expect to find the policy by known attributes # something like this: # Policy.find_by_account_category_and_name(....).should_not be_nil end it "creates a new violation" do record # same as the policy - find the Violation by known attributes end it "updates most_recent_violations" do record # query for most recent violations and expect the violation # to be found end it "updates the violation count" do expect { record }.to change {content.unresolved_violation_count}.by(1) end # etc, etc end Yes, this means that the process needs to happen more than once, but each example becomes much easier to grok. WDYT? Thanks, > Ijonas. > > On Mon, Jan 4, 2010 at 11:16 AM, David Chelimsky <dchelim...@gmail.com>wrote: > >> On Mon, Jan 4, 2010 at 4:33 AM, Ijonas Kisselbach < >> ijonas.kisselb...@gmail.com> wrote: >> >>> Hi, >>> >>> I'm struggling with structuring my specs describing a large process in my >>> app. There are multiple paths of execution through that process each of >>> which I'm trying to describe using a different rspec context, eg. >>> >>> describe Violation do >>> context ", when nothing has changed since the last run" >>> context ", when new content has been created, but policies remain the >>> same" >>> context ", when new policies are activated, but content remains the >>> same" >>> end >>> >>> Each of the three scenarios/context above have got a bunch of "it >>> should..." blocks in it which in turn contain a whole bunch of >>> should_receives and should_not_receives on various mocked objects, thereby >>> exercising the functionality of the large process. >>> >>> I would like the context to read as follows: >>> >>> context ", when new policies are activated, but content remains the same" >>> do >>> it "should create the new policy" do >>> # a whole bunch of expectations testing the policy creation part of >>> the process >>> end >>> it "should create a new violation and location" do >>> # a whole bunch of expectations testing the violation creation part >>> of the process >>> end >>> it "should resolve previous violations" do >>> # a whole bunch of expections testing retrieval of previous >>> violations and performing updates on them >>> end >>> .... >>> end >>> >>> The problem is: if I compartmentalize my expectations into the individual >>> it-should-blocks then something will fail in the execution of the large >>> process, typically caused by a mock not being setup. If I lump all my >>> expectations in the before(:each)-block then the whole thing springs to >>> life, but I lose my compartmentalization of the specs and the whole thing >>> becomes unreadable. >>> >>> I guess I'm looking for help and advice on how best combat the lumping of >>> expectations into the before-block. Should I separate my stubbing from my >>> expectations ? >>> >>> Many thanks for your advice. >>> >> >> I'd need to see the actual code to respond in any precise way here, but >> generally, it sounds like you're specifying too much about the >> implementation rather than the outcomes. What happens if you eliminate all >> of the mocks in these examples and just have expectations like >> "Policy.find(@policy_id).should_not be_nil"? >> >> David >> >> >>> >>> (I'm using rspec 1.2.9 and Rails 2.2.2 on OSX) >>> >>> Regards, >>> Ijonas. >> >> >> _______________________________________________ >> rspec-users mailing list >> rspec-users@rubyforge.org >> http://rubyforge.org/mailman/listinfo/rspec-users >> > > > _______________________________________________ > rspec-users mailing list > rspec-users@rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
_______________________________________________ rspec-users mailing list rspec-users@rubyforge.org http://rubyforge.org/mailman/listinfo/rspec-users