开发者

C# Unit Test Design Issue: How to reduce redundancy in unit test writing?

开发者 https://www.devze.com 2023-04-13 03:03 出处:网络
Here is my c# unit test design issue: I have one test that I want to run on some code that modifies a file. My test will run the code that modifies the file, then check the result. Pretty straight fo

Here is my c# unit test design issue:

I have one test that I want to run on some code that modifies a file. My test will run the code that modifies the file, then check the result. Pretty straight forward so far...

The issue is, I have about 10 files (soon to be a lot more) that I want to run the same unit test against. I dont want to write a new unit test for each file, when the test itself is really the same.

I could write a single test that queries the files in the folder and then runs the test logic on each file, but using this method would only report one pass/fail result开发者_开发问答 for the entire set of files.

Id like to create some sort of dynamic system where every file that I place in a particular folder gets ran though this same unit test. So if 25 files are in the folder, the test gets ran 25 times, and the unit test reults report that 25 tests were ran, and includes seperate pass/fails for each.

Any ideas how or if this can be done in a c# unit test? Or with a nunit test?

Thanks! And I hope this is not a duplicate question. I looked around, but I could not find anything.


It sounds like what you need is a parameterised test case: see http://www.nunit.org/index.php?p=testCaseSource&r=2.5.

So:

[TestFixture]
public class Tests
{
    static string[] FileNames = new string[] 
                    { "mary.txt", "mungo.txt", "midge.txt" };

    [Test, TestCaseSource("FileNames")]
    public void TestMethod(string fileName)
    {
        Assert.That(File.Exists(fileName));
    }
}

The [TestCaseSource] attribute tells NUnit to get the values of the string parameter from the string array.

That approach, however, requires static constants for filenames. If you'd rather have a programmatic approach that reads the files from a database or suchlike try a factory class like so:

[TestFixture]
public class Tests
{
    [Test, TestCaseSource(typeof(FilenameFactory), "FileNames")]
    public bool FileCheck(string fileName)
    {
        return File.Exists(fileName);
    }
}

public class FilenameFactory
{
    public static IEnumerable FileNames
    {
        get
        {
            foreach (var filename in 
                   Directory.EnumerateFiles(Environment.CurrentDirectory))
            {
                yield return new TestCaseData(filename).Returns(true);
            }
        }
    }
}

The TestCaseData class generates "test cases" which have expectations that can be set through a fluent interface.


Parameterized tests ( http://www.nunit.org/index.php?p=parameterizedTests&r=2.5 ) could be of use to you depending how you are doing them.

Example of TestcaseAttribute which you can use use or there is also TestCaseSourceAttribute

[TestCase(12,3,4)]
[TestCase(12,2,6)]
[TestCase(12,4,3)]
public void DivideTest(int n, int d, int q)
{
  Assert.AreEqual( q, n / d );
}

You get the advantage of writing and maintaining one test, but the results are for each case.


Another option is to use T4 templates to dynamically generate tests for you based on the number of files in your directory. Add this ".tt" file to your unit test project.

Now whenever you do a build which should happen just before you press the "Run all tests in solution" button in visual studio, it should generate unit tests for all the files in the directory with the file name in the unit test. Then your test run should have a nice list of all the files it tested and their statuses.

<#@ template debug="false" hostspecific="true" language="C#v3.5" #>
<#@ assembly name="System.Core.dll" #>
<#@ assembly name="System.Data.dll" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Linq" #>
<#@ output extension=".cs" #>
<#
            string inputDirectory = @"d:\temp";
            var files = System.IO.Directory.GetFiles(inputDirectory);
#>
using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace TestProject1
{
    [TestClass]
    public class UnitTest1
    {
        <# foreach (string filePath in files) { #>
        [TestMethod]
        public void TestingFile_<#=System.IO.Path.GetFileNameWithoutExtension(filePath).Replace(' ','_').Replace('-','_')#>()
        {
        File currentFile = System.IO.File.Open(@"<#= filePath #>", FileMode.Open);
        // TODO: Put your standard test code here which will use the file you opened above
        }
        <# } #>
    }
}


First of all, having a test depend on external sources like files on disk is not strictly unit testing (opinion).

What you're looking for is a data-driven testing approach and then you should look for tools that support it, like MSTest or MBunit. (Follow the links for more info).

Then you can do something like this (using MBunit):

[TestFixture]
public class MyTestFixture
{
  [Test]
  public void WordCounter([TextData(ResourcePath = "Data.txt")] string text)
  {
      var wordCounter = new WordCounter(text);
      int count = wordCounter.Count("Firecrest");
      Assert.AreEqual(4, count); // Should not include the plural form "Firecrests".
  }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号