Need help with TDD, stubs and mocks

I’m writing a script to process a directory structure and some files
within it. The process depth-first searches the directory tree from
some root and looks for a Manifest file. When it finds it, it
processes the file (XML plist, containing keys for filenames and
paths) and records some information about the files referenced in the
manifest. This recorded information then gets posted to a web service
via SOAP.

Actually, I already wrote this using my usual top-down style. First,
I wrote the code to depth-first search the directories. This included
code to test all entries in a directory (using #file? and
#directory?). Next I wrote the code to detect the manifest file. Then
I used the plist gem to read it into memory (great gem). Then I wrote
the code to do my magic on the files referenced in the plist. Etc.

I just iterated through my requirements until I had a finished product.

When I finished I decided to write tests to verify each method.
However, the main entry point into the script starts off by doing the
directory traversal which then feeds into every other step. I can’t
call the method without running all of its dependent methods (which
essentially runs the whole program). This strikes me as my first clue
that I probably did this wrong.

So now I’d like to rewrite it using TDD.

I need some advice from the TDD experts out there.

  1. Is it fair to say that I should rewrite bottom-up? That is, start
    with methods that are independent of others. For example, assume no
    subdirs and just get a list of entries from the current directory.
    Then write the method to iterate those entries. Then write one to
    test if the entry is a file or a directory. Etc.

  2. Do you generally keep all methods in a class independent of each
    other? How do you write, and then test, methods that have
    dependencies on each other (and therefore cause side effects)?

  3. How does one mock or stub out a SOAP call? What’s the difference
    between a stub and a mock?

  4. How do you test a method that utilizes an instance variable that
    was set somewhere else? E.g. #methodA calculates @result. #methodB
    retrieves @second_result. #methodC compares @result and @second_result.

Instead of treating these as global to the class instance, should I
be passing them as method parameters?

I appreciate any and all insight. I’m hoping to continually improve
as a programmer so I can answer these questions instead of always
asking them. :slight_smile:

cr

cr wrote:

When I finished I decided to write tests to verify each method.
However, the main entry point into the script starts off by doing the
directory traversal which then feeds into every other step. I can’t
call the method without running all of its dependent methods (which
essentially runs the whole program). This strikes me as my first clue
that I probably did this wrong.

Code not done test first will often be hard to test. I think we just
discovered that.

  1. Is it fair to say that I should rewrite bottom-up? That is, start
    with methods that are independent of others.

When I do TDD, I start with very simple cases and work toward more
general cases. Both bottom-up and top-down work, I tend to do
outside-in (i.e. start at both the top and bottom and work toward the
middle).

  1. Do you generally keep all methods in a class independent of each
    other? How do you write, and then test, methods that have
    dependencies on each other (and therefore cause side effects)?

Dependencies? Like “You Must Call Method A before Method B”? I try to
avoid those kinds of dependencies when possible. Sometimes the
semantics of the object naturally introduce them (e.g. you usually have
to push something in order to pop something from a stack).

  1. How does one mock or stub out a SOAP call? What’s the difference
    between a stub and a mock?

Is there an object that you use to perform the soap call? If so, just
replace the object with a Stub or Mock.

Stub VS Mock: (Terminalogy varies, but the following is a common
distinction) Mocks check their calls for correctness, stubs don’t.
Stubs are used to provide external behavior that might not exist in a
test environment. Mocks are used to verify that you are actually
calling particular methods with paricular arguments.

Note that using this terminology allows a single object to mock some
methods and stub others. I do this alot. If you divide methods into
two camps: those that return values (queries) and those that do things
(commands), I usually stub queries and mock commands.

  1. How do you test a method that utilizes an instance variable that
    was set somewhere else? E.g. #methodA calculates @result. #methodB
    retrieves @second_result. #methodC compares @result and @second_result.

Construct your test case so that methodA and methodB are called before
methodC does its work.

Example:

def test_comparison
thing = Thing.new
thing.methodA
thing.methodB
assert_equal ExpectedResult, thing.methodC
end

– Jim W.

unknown wrote:

On Jun 5, 2006, at 10:57 AM, Jim W. wrote:

def test_comparison
thing = Thing.new
thing.methodA
thing.methodB
assert_equal ExpectedResult, thing.methodC
end

Jim,

thanks for your response. I do need some additional clarification on
this final point. The way I see your answer, you are NOT suggesting I
pass instance variables as parameters.

I don’t have enough information to make a recommendation one way or
another. As a general rule of thumb, I would try to avoid order
dependencies in methods, but if you have them, its not an inordinate
burden for testing.

Instead, I should enforce the
order of operations for my methods and allow them “global” (in this
class instance) access to the instance variables.

Your use of “global” is confusing to me. To you mean access to the
variable outside of the object?

Without further details, all one can do is make general statements. My
recommendation: determine the responsibilities of the object and make
sure the methods for that object are adequate to allow it to perform
those responsibilities.

– Jim W.

On Jun 5, 2006, at 10:57 AM, Jim W. wrote:

def test_comparison
thing = Thing.new
thing.methodA
thing.methodB
assert_equal ExpectedResult, thing.methodC
end

Jim,

thanks for your response. I do need some additional clarification on
this final point. The way I see your answer, you are NOT suggesting I
pass instance variables as parameters. Instead, I should enforce the
order of operations for my methods and allow them “global” (in this
class instance) access to the instance variables.

I still see this as somewhat problematic if there is a long chain of
“custody” in between where the instance variable gets set and where
it gets used again by a later method. I’ll have to think on this a
bit more.

BTW, I really appreciated the distinctions you made on mocks versus
stubs. I think I get it now. Now all I need to do is repeat this a
thousand times to imprint it on my brain.

Time to test!

cr