[rspec-users] 2nd attempt at mocking and stubbing

David Chelimsky dchelimsky at gmail.com
Sat Sep 6 23:00:20 EDT 2008


On Sat, Sep 6, 2008 at 9:57 PM, David Chelimsky <dchelimsky at gmail.com> wrote:
> On Sat, Sep 6, 2008 at 4:48 PM, Nick Hoffman <nick at deadorange.com> wrote:
>> On 2008-09-06, at 15:58, David Chelimsky wrote:
>>>
>>> Well, without changing the underlying semantics, you can clean up the
>>> syntax a bit like this:
>>>
>>>  mock_property1 = stub('property', :address => '400 Bloor Street',
>>> :latitude => 12.34, :longitude => 56.78)
>>>
>>> Of course, that doesn't address your question :)
>>
>> That makes the specs much easier to read!
>>
>>> Here's another thought that doesn't answer your question - this line
>>> in the code:
>>>
>>>  add_marker p.address, p.latitude, p.longitude,
>>> generate_marker_contents(p)
>>>
>>> is resulting in a situation where you have to do a lot of setup in
>>> order to isolate the object under test. The line exhibits the Feature
>>> Envy Code Smell, which is the odor emitted by one object depending on
>>> another object's data.
>>
>> RentalMap#add_properties does have feature envy. However...
>>
>>> If I were coding by example, I'd probably start w/ a simple example like
>>> this:
>>>
>>> describe '#add_properties' do
>>>  it 'should add one property to the map' do
>>>   map = RentalMap.new @map_name, @latitude, @longitude
>>>   mock_property = mock 'property'
>>>   Property.stub!(:find).and_return [mock_property]
>>>
>>>   mock_property.should_receive(:add_marker_to).with(map)
>>>
>>>   map.add_properties
>>>  end
>>> end
>>>
>>> This defines how I'd like to be able to "talk" to the Property, and
>>> results in an implementation like this:
>>>
>>>  p.add_marker_to(map)
>>>
>>> Now all the additional behaviour is pushed to the Property, for which
>>> you can write code examples with the details of its own data rather
>>> than having to stub so much of its data for use in the current
>>> example.
>>
>> I believe that the process of adding a marker (IE: Property) to a RentalMap
>> should be a feature of the RentalMap model, rather than the Property model.
>> From a Property's perspective, a property has nothing to do (IE: no
>> interactions) with RentalMaps. From a RentalMap's perspective, a RentalMap
>> has lots to do with Properties, because it needs to ask a Property for
>> information so that it can add a marker to itself.
>
> Sounds like you're letting adherence to a mental model overrule what
> the code is actually telling you. The code is telling you that the
> model is flawed. I'd listen to it.
>
> Personally, I don't see any conceptual, philosophical problem with a
> Property knowing it is on a Map - doesn't have to be a RentalMap, just
> a Map. If you can accept that, then you can take the next step and do
> a little double dispatch:
>
> class Property
>  def add_to(map)
>    map.add_marker address, latitude, longitude, contents
>  end
> end

Or, better yet:

class Property
 def add_marker_to(map)
   map.add_marker Marker.new(address, latitude, longitude, contents)
 end
end

That reduces the surface contact between the Property and the Map even more.

>
> The map could be RentalMap, a ListingMap, an EventsMap, etc, etc.
>
>>
>> To make an analogy, do I put on a shirt, or does a shirt put itself on me?
>
> You are human. Programs are not. Seeing as a Person object and a Shirt
> object can be programmed to behave as we wish, I'd suggest that there
> might be fewer dependencies and a simpler series of instructions if
> the shirt object put itself on the person object.
>
> While Objects can sometimes do a decent job of modeling the real
> world, that's not why they exist. They were born to make software more
> ... soft. Guidelines like Law of Demeter, Tell Don't Ask and DRY
> didn't come out of nowhere. None of them are 100% applicable all the
> time, but when they are violated, their resulting cries should at
> least be a red flag.
>
> FWIW,
> David
>
>>
>> Thanks again for your opinions, David!
>> Nick
>> _______________________________________________
>> rspec-users mailing list
>> rspec-users at rubyforge.org
>> http://rubyforge.org/mailman/listinfo/rspec-users
>>
>


More information about the rspec-users mailing list