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

David Chelimsky dchelimsky at gmail.com
Sat Sep 6 22:57:50 EDT 2008


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

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