Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Learning TDD with a simple example

Tags:

I'm attempting to learn TDD but having a hard time getting my head around what / how to test with a little app I need to write.

The (simplified somewhat) spec for the app is as follows:

It needs to take from the user the location of a csv file, the location of a word document mailmerge template and an output location.

The app will then read the csv file and for each row, merge the data with the word template and output to the folder specified.

Just to be clear, I'm not asking how I would go about coding such an app as I'm confident that I know how to do it if I just went ahead and started. But if I wanted to do it using TDD, some guidance on the tests to write would be appreciated as I'm guessing I don't want to be testing reading a real csv file, or testing the 3rd party component that does the merge or converts to pdf.

I think just some general TDD guidance would be a great help!

like image 384
DavidGouge Avatar asked Dec 09 '10 14:12

DavidGouge


1 Answers

I'd start out by thinking of scenarios for each step of your program, starting with failure cases and their expected behavior:

  • User provides a null csv file location (throws an ArgumentNullException).

  • User provides an empty csv file location (throws an ArgumentException).

  • The csv file specified by the user doesn't exist (whatever you think is appropriate).

Next, write a test for each of those scenarios and make sure it fails. Next, write just enough code to make the test pass. That's pretty easy for some of these conditions, because the code that makes your test pass is often the final code:

public class Merger {      public void Merge(string csvPath, string templatePath, string outputPath) {         if (csvPath == null) { throw new ArgumentNullException("csvPath"); }     } } 

After that, move into standard scenarios:

  • The specified csv file has one line (merge should be called once, output written to the expected location).

  • The specified csv file has two lines (merge should be called twice, output written to the expected location).

  • The output file's name conforms to your expectations (whatever those are).

And so on. Once you get to this second phase, you'll start to identify behavior you want to stub and mock. For example, checking whether a file exists or not - .NET doesn't make it easy to stub this, so you'll probably need to create an adapter interface and class that will let you isolate your program from the actual file system (to say nothing of actual CSV files and mail-merge templates). There are other techniques available, but this method is fairly standard:

public interface IFileFinder { bool FileExists(string path); }  // Concrete implementation to use in production public class FileFinder: IFileFinder {     public bool FileExists(string path) { return File.Exists(path); } }  public class Merger {     IFileFinder finder;     public Merger(IFileFinder finder) { this.finder = finder; } } 

In tests, you'll pass in a stub implementation:

[Test] [ExpectedException(typeof(FileNotFoundException))] public void Fails_When_Csv_File_Does_Not_Exist() {      IFileFinder finder = mockery.NewMock<IFileFinder>();     Merger      merger = new Merger(finder);     Stub.On(finder).Method("FileExists").Will(Return.Value(false));      merger.Merge("csvPath", "templatePath", "outputPath"); } 
like image 170
Jeff Sternal Avatar answered Oct 16 '22 20:10

Jeff Sternal