Definitely helpful. Thanks, its much appreciated. On Mon, Jan 4, 2010 at 1:08 PM, David Chelimsky <dchelim...@gmail.com>wrote:
> On Mon, Jan 4, 2010 at 7:06 AM, Ijonas Kisselbach < > ijonas.kisselb...@gmail.com> wrote: > >> Hi David, >> >> Thanks for the suggestions... Yes I am mocking to avoid DB access, but if >> the cost is DB access vs. readability: I'll choose readability. >> >> Would you use something like Factory Girl or Machinist to setup the DB? To >> avoid too much mocking and to avoid old-skool fixtures. >> > > YES! > > Thanks for the help. >> > > Assuming it was helpful, you're welcome. > > Cheers, > David > > >> >> On Mon, Jan 4, 2010 at 12:56 PM, David Chelimsky <dchelim...@gmail.com>wrote: >> >>> 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 >>> >> >> >> _______________________________________________ >> 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