views:

37

answers:

3

I have a test method that tests the ToString() method of a class against known good outputs.

    /// <summary>
    ///A test for ToString
    ///</summary>
    [TestMethod()]
    public void ToStringTest()
    {
        string input = System.IO.File.ReadAllText(@"c:\temp\input2005.txt");
        MyClass target = new MyClass(input);
        string expected = System.IO.File.ReadAllText(@"c:\temp\output2005.txt");
        string actual;
        actual = target.ToString();
        Assert.AreEqual(expected, actual);
    }

The method works great, but I already have several pairs of input/output files. Experience tells me that I don't want to write a separate test method for each pair. I also don't want to loop through each pair of files because I won't know which pair caused the test to fail. What do I do?

A: 

If you wish to test all pairs of files, you could put the file that failed as a message to the assertion:

foreach(file in filenames)
{
    /* run your test */
    Assert.AreEqual(expected, actual, "Failure occured on file: " + file);
}

This would print out a message telling you which file the failure occured on.

Additionally, you could specify your strings inside of the test itself instead of putting them in extrenal files. I'm not sure how your tests are setup but if you did that you wouldn't have to worry about the external depencies of the file paths:

MyClass target = new MyClass("myTestString");
string actual = target.ToString();
string expected = "MyExpectedString";
Assert.AreEqual(expected, actual);

This would keep all of your test data together.

Daniel Brotherston
This looks like it will work out of the box in Visual Studio. BTW, the files weigh several KB each; I have to keep them out of the source code.
Craig Grant
Ahh, that would be one reason to do it this way, even if its a little different. I believe the VS Test framework that comes out of the box has something similar to what Kevin McHahon describes, but I've never used it before. You might also have to have some type of database for it to work anyways.
Daniel Brotherston
I'll get there. This is actually my first test and I'm enjoying it. :)
Craig Grant
A: 

The MbUnit framework has the concept of row tests and I believe there is an NUnit Add-In for 2.4 that provides similar functionality for NUnit. Using MbUnit syntax it would look something like this:

/// <summary>
///A test for ToString
///</summary>
[Test]
[RowTest(@"c:\temp\input2005.txt", @"c:\temp\output2005.txt")]
[RowTest(@"c:\temp\input2006.txt", @"c:\temp\output2006.txt")]
[RowTest(@"c:\temp\input2007.txt", @"c:\temp\output2007.txt")]
public void ToStringTest(string inputFile, string outputFile)
{
    string input = System.IO.File.ReadAllText(inputFile);
    MyClass target = new MyClass(input);
    string expected = System.IO.File.ReadAllText(outputFile);
    string actual;
    actual = target.ToString();
    Assert.AreEqual(expected, actual);
}
Kevin McMahon
+1  A: 

You could use a loop inside your test but you will only get one pass or failure for all of them. Some test frameworks will generate and run a separate test for each set of inputs specified like this:

[Test]
[Row(@"c:\temp\input2005.txt", @"c:\temp\output2005.txt")]
[Row(@"c:\temp\input2006.txt", @"c:\temp\output2006.txt")]
[Row(@"c:\temp\input2007.txt", @"c:\temp\output2007.txt")]
public void ToStringTest(string inputPath, string expectedPath)
{
    string input = System.IO.File.ReadAllText(inputPath);
    MyClass target = new MyClass(input);
    string expected = System.IO.File.ReadAllText(expectedPath);
    string actual;
    actual = target.ToString();
    Assert.AreEqual(expected, actual);
}

The above will work with MbUnit but I believe many of the other frameworks also support similar features.

As an aside, unit tests shouldn't really touch the file system as you can get test failures due to external factors (such as a file being locked) which makes your tests unreliable.

GraemeF