Home     |     .Net Programming    |     cSharp Home    |     Sql Server Home    |     Javascript / Client Side Development     |     Ajax Programming

Ruby on Rails Development     |     Perl Programming     |     C Programming Language     |     C++ Programming     |     IT Jobs

Python Programming Language     |     Laptop Suggestions?    |     TCL Scripting     |     Fortran Programming     |     Scheme Programming Language


 
 
Cervo Technologies
The Right Source to Outsource

MS Dynamics CRM 3.0

Python Programming Language

Refactoring test units after an extract method


This is not strictly python related, but it's not strictly TDD related
either. Anyway, here it goes.

There's something that I was never quite sure how to handle with test
units: How to handle the test unit refactoring after a method
extraction.

Let's say that you have a function foo() that does A and B. You have
tests for foo() that check that A and B are executed properly. Then,
you add another function, bar(), that needs to do B, so you add a
third function, baz() that does B and make foo() and bar() call baz().

How to you handle the tests? Copy over the tests you had for foo() and
apply them to bar()? I don't like copy and pasting code. Move the B
related tests to baz()'s tests? Then your tests wouldn't fail if you
stopped calling baz() in foo() and bar().

What I do right now is that I mock baz() and verify that it is called
in foo() and bar(), with the right arguments. Then I move the B
related tests to baz(). It kind of works, but somehow, it doesn't feel
like the ideal solution to me. But then again, it's kind of the same
thing as if baz() was a third party function: You have to mock it to
test foo() and bar() properly without testing the third party code.

What do you people think?

--- Virgil Dupras <hardcoded.softw@gmail.com>
wrote:

> How to you handle the tests? Copy over the tests you
> had for foo() and
> apply them to bar()? I don't like copy and pasting
> code. Move the B
> related tests to baz()'s tests? Then your tests
> wouldn't fail if you
> stopped calling baz() in foo() and bar().

I recently had an example where class A used class B,
which used class C, which used class D, which used OS
service E, etc.  I had mock versions of B, C, D, and
E.  The overall design of the module was kind of like
a network stack, where each module theoretically only
depended on the services of the module beneath it in
the stack.  

So many of the tests for A used a real B, but a mock
C.

Many of the tests for B used a real C, but a mock D.

Many of the tests for C used a real D, but a mock E.

But I also wanted to test that my abstractions weren't
leaky, e.g. that there weren't some implementation
details of C or lower that broke A.  So certain loops
in my test for A would also plug in a real C.

Finally, some of the test for A would also use a mock
B.

I was able to mostly avoid copy-and-pasting of tests
by taking advantage of Python's dynamic nature.
Although this is oversimplifying things a bit, you can
do things like this:

for b_is_mocked, c_is_mocked, d_is_mocked in [
     (True, True, True),
     (True, True, False),
     (False, False, False), # etc.
     ]
     # do setup
     test1()
     test2()
     test3()
     test4()

___________________________________________________________________________ _________
Sick sense of humor? Visit Yahoo! TV's
Comedy with an Edge to see what's on, when.
http://tv.yahoo.com/collections/222

Add to del.icio.us | Digg this | Stumble it | Powered by Megasolutions Inc