[rspec-users] Mocking: brittle specs and tight coupling?
Phlip
phlip2005 at gmail.com
Sun Apr 12 20:23:45 EDT 2009
David Chelimsky wrote:
>> Another tip: To TDD a new feature, don't clone a high-level test which calls
>> code which calls code which calls the code you need to change.
>
> FWIW, what you propose is the exact opposite of BDD, which suggests we
> start at the highest levels and work our way in.
My current day-job's most important project has a test suite that suffered from
abuse of that concept. The original team, without enough refactoring, were
cloning and modifying very-high-level tests, making them longer, and using them
to TDD new features into the bottom of the models layer. Don't do that.
> How can you know what the lowest level code is supposed to do before
> you have higher level code invoking it? You can certainly make good
> guesses, and they might end up being good choices in the end, but they
> tend to bind you to a pre-determined design.
That sounds like James Kanze's over-educated arguments against TDD:
> Phlip wrote:
>> James Kanze wrote:
>> > In particular, you can't
>> > write a single line of code (unit test or implementation) before
>> > you know what the function should do,
>
>> I didn't bring up TDD, but if you are curious enough about it
>> to keep asking these entry-level FAQs,
>
> I'm not asking anything. I'm simply stating an easily
> established fact, which wishful thinking seems to cause some
> people to ignore. Tests definitly have their role, but until
> you know what the code should do, you can't begin to write them.
> And until you've written something down in black and white, you
> don't know it.
From there, he'll wander off into "too smart to just try it" bullshit...
> Your recommendation also starts with cloning a pre-existing example,
> so I'm assuming this is a very specific sort of situation, where you
> have a certain amount of code in place. What about when you are
> starting a project for the first time?
Programming bottom-up gives you decoupled lower layers. Top-down gives you a way
to tunnel from a new View feature into the code that supports it. The goal is
you _could_ start a new feature either way, and you get the benefits of both
techniques.
I thought of describing that specific tip while adding "any!" to assert_xhtml.
It would have been too easy to start with the high-level tests:
def test_anybang_is_magic
assert_xhtml SAMPLE_LIST do
ul.kalika do
any! 'Billings report'
end
end
assert_xhtml_flunk SAMPLE_LIST do
without! do
any! 'Billings report'
end
end
end
Some of my features indeed started there, and some of them indeed do not yet
have low-level tests.
But the entire call stack below that also at least has tests on each layer -
except the actual code which converts a tag like select! into the fragment of
XPath which matches //select[]. Oh, and that code around it had grown a little
long. So in this case, I started there, and refactored out the single line that
needed the change:
def translate_tag(element)
element.name.sub(/\!$/, '')
end
Then I can TDD translate_tag directly:
def test_any_element
bhw = assemble_BeHtmlWith{ any :attribute => 'whatever' }
element = bhw.builder.doc.root
assert{ bhw.translate_tag(element) == 'any' }
bhw = assemble_BeHtmlWith{ any! :attribute => 'whatever' }
element = bhw.builder.doc.root
assert{ bhw.translate_tag(element) == '*' }
end
...
def translate_tag(element)
if element.name == 'any!'
'*'
else
element.name.sub(/\!$/, '')
end
end
Only then I wrote the high-level tests, and they passed.
Note that RSpec requires the constructor to BeHtmlWith to be a little ...
fruity, so I wrapped it and its Builder stuff up into assemble_BeHtmlWith...
--
Phlip
More information about the rspec-users
mailing list