On Mon, Jan 4, 2010 at 5:26 AM, Ijonas Kisselbach <
[email protected]> 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 <[email protected]>wrote:
>
>> On Mon, Jan 4, 2010 at 4:33 AM, Ijonas Kisselbach <
>> [email protected]> 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
>> [email protected]
>> http://rubyforge.org/mailman/listinfo/rspec-users
>>
>
>
> _______________________________________________
> rspec-users mailing list
> [email protected]
> http://rubyforge.org/mailman/listinfo/rspec-users
>
_______________________________________________
rspec-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users