tags:

views:

97

answers:

2

I am new (as of today) to NUnit and TDD. However, I am very interested in the technique and I am trying to learn. I have a test case I would like to read from a file if it exists, otherwise I will grab from the registry. How do I test both conditions? Here is an example of the code I would like to write a test case for:

    public static string ReferenceDirectory
    {
          get
        {
            string referenceDir = Path.Combine(_summitDataDirectory, REFERENCES_DIR); ;
            //If Windows Compliant data location does not exist, fall back on registry values
            if (!Directory.Exists(referenceDir))
                referenceDir = Path.Combine(GetRegistryValue("appPath"), @"Data\Databases\");                                    

            return referenceDir;
        }
    }

What I'm confused about is do I have to create two test cases: one in which I create the directory and another in which I remove the directory and read from registry? Also, at some point the registry will be cleaned and the value no longer will be in the registry which will mean this code is no longer valid unless I create the value in the registry.

To provide larger context, this code is for migrating our app to Vista/Win7 and thus I need to support the legacy path to the registry until all users are migrated.

Note: specific test code examples would be helpful as I'm completely new to NUnit.

EDIT: Modified code example based on comments.

+1  A: 

Hi there.

If I was testing this code, then here is my list of scenarios.

  • Test code when referenceDir does exist.
  • Test code when referenceDir does not exist and registry value does exist.
  • Test code when referenceDir does not exist and registry value does not exist.

I would want to know what is the code going to do in each scenario. So to answer you first part, I would say you need to write three separate unit tests.

As for the situation where the registry key might be cleaned, I don't know what to recommend - if the key's not there, what could you use as plan B?

EDIT: I just noticed that referenceDir is not set to a value in your code, is there some code missing from your example, since Directory.Exist(referenceDir) will always fail.

Cheers. Jas.

Jason Evans
Good catch Jason, I made a last second edit that proved to me erroneous. I changed the code if that helps you any. That may also answer your question about if the registry is cleaned. Essentially the flow is supposed to be:if new directory exists use that directoryelse use directory location specified in registryHope that helps!
Blake Blackwell
The suggested tests above are good, but let's be clear--they're integration tests, not unit tests. TDD forces an object and interface explosion, and this is something you're going to have to get comfortable with. This object explosion also one reason why everyone's so crazy about R#.
Peter Seale
+1  A: 

Your tests should isolate and NOT test the MS methods for the directory or the registry. You can assume that Microsoft has coded them correctly. The easy way most people get around this is to move the calls to methods that can be overridden by a shunted class in the test so something like:

protected virtual bool DirectoryExists(string path){
   return Directory.Exists(path);
}

then in your tests, rather than test the class your dealing with; test a shunted class that extends the class under test and then override with:

protected override bool DirectoryExists(string path){
       return true; // or false or set a instance variable that you can manipulate
    }

The point is the last thing you want is for your test to have to create files or registry entries. That gets messy and slow.

and yes, this all means your property probably can't be static anymore.

!Edit for question If you absolutely need to keep the class static you can do something like this:

public class Foo{
private IDirectoryAccessor dir;

public static Foo(){
   dir = new MicrosoftDirectoryAccessor();
}    

public static SetDirectoryAccessor(IDirectoryAccessor dir){
  set this.dir = dir;
}

public static string ReferenceDirectory
{
      get
    {
        string referenceDir = Path.Combine(_summitDataDirectory, REFERENCES_DIR); ;
        //If Windows Compliant data location does not exist, fall back on registry values
        if (!dir.Exists(referenceDir))
            referenceDir = Path.Combine(GetRegistryValue("appPath"), @"Data\Databases\");                                    

        return referenceDir;
    }
}

You can always put the setter for the access object in a tested subclass

ryber
Perhaps I should ask the question of whether there is even a need for a unit test on these methods? If it is going to change the definition of the class (from static), and mocking up file/registry settings is too costly, is the test necessary?
Blake Blackwell
It's not that costly, you can do it in a few minutes. And static classes are generally evil...particularly as you get more and more into TDD...it becomes necessary to abstract and keep yourself SOLID. If you really need to keep it static for some reason, you can create a IO wrapper object with a interface that the static class holds onto and can be substituted for different implementations.
ryber
Learning TDD is not easy, and it's definitely more painful than sticking with your usual style--but stick with it anyway.
Peter Seale
Thanks guys! I'll keep plugging away. I appreciate your help!
Blake Blackwell