views:

133

answers:

4

I've been out of touch with TDD for some time, and am very rusty. I'd appreciate some suggestions on how to TDD the method described below.

The method must find a web.config file in a user supplied application directory. It must then extract and return a connection string from that config file.

It returns null if for any reason the connection string isn't found, be it a bad path, no web.config, or no connection string in web.config.

My initial thoughts are to write a test with setup that creates a directory and writes a web.config file with a connection string. The test would then call my method with the created path and expect a non-null value back, and my initial test run would fail because my method stub always returns null.

Then, implement the method, and run the test expecting a pass. Then, as a pre-test (I forget the term), delete the created directory, and call the method expecting a null value.

A: 

Make the object that hold you method (or the method itself) dependent on a IConfigLoader of some sort, that you would be able to mock :

public interface IConfigLoader
{
    XmlReader LoadAppConfigFrom(string path);
}

Use it from your method to get the XML file you want to parse.

Romain Verdier
+4  A: 

First, I wouldn't have the method both find the file and extract the connection string. If your framework doesn't already have a method to determine if a file exists in a given directory, write a method to do then, once you have a file, write a method to extract the connection string from an open stream. For testing, then, you could supply a memory stream instead of having to actually create a directory and file.

Second, if you aren't depending on a failed compile being your first failing test, then write your first attempt at the method to throw a NotImplementedException. It's a small step, but when you write your first test, at least it will fail. Of course, the first test on an empty stream will expect it to return null and the first code you write will be return null, but that's ok. Your next test will force you to change it. Continue on from there until you've got your completed methods.

tvanfosson
Paragraph 1: This is a very simple case, and I would prefer to encapsulate the whole connection string task in one method, even if it skirts the single responsibility guideline.Paragraph 2: Good point, I've gone that route.
ProfK
@profk: if you mix responsibilities you will find TDD much harder. TDD in this case is doing its job - guiding you towards a different (perhaps subjectively better) design.
Jim Arnold
+3  A: 

You appear to have several TestCases with several distinct setUp fixtures.

  1. The FoundDirectory TestCase. The setUp creates the expected, valid file.

    This can have several subclasses.

    1. A connection string not found TestCase. The setUp creates the expected, but invalid file.

    2. A bad path TestCase. The setUp creates the expected, but invalid file.

    3. A no web.config TestCase. The setUp creates the expected, but invalid file.

    4. A no connection string in web.config TestCase. The setUp creates the expected, but invalid file.

  2. The DidntFindDirectory TestCase. The setUp assures that the directory doesn't exist.

  3. The DidntFindFile TestCase. The setUp creates the directory but no file.

S.Lott
I like you approach, but your point 1.1 seems to sort of duplicate point 1.4. Did you mean set up a file without a connection string element, where 1.4 has an empty connection string element?
ProfK
I'm guessing at the test cases from the problem description. I don't know the real differences between the test cases -- I'm just guessing from the words in the problem.
S.Lott
A: 

I suggest that the story in your question mixes several issues:

  1. finding and opening a file,
  2. loading data into a "configuration" (however represented)
  3. attempting to get a specific parameter from a "configuration"

Point 3 is now a matter of how a Configuration behaves, and can be developed in TDD fashion.

Point 2 is now a matter of how a Configuration is constructed (e.g by a ConfigurationLoader), and can be developed in TDD fashion (e.g. against a StringReader).

Point 1 is now a matter of whether you can open a Reader for a specified file path. It is easy to add after completing point 2.

joel.neely