C#单元测试设计问题:如何减少单元测试写入的冗余?

时间:2011-10-14 05:38:49

标签: c# .net unit-testing nunit

这是我的c#单元测试设计问题:

我想在一些修改文件的代码上运行一个测试。我的测试将运行修改文件的代码,然后检查结果。到目前为止非常直接...

问题是,我有大约10个文件(很快就会更多)我想要运行相同的单元测试。当测试本身真的相同时,我不想为每个文件编写一个新的单元测试。

我可以编写一个查询文件夹中文件的测试,然后在每个文件上运行测试逻辑,但使用此方法只会报告整个文件集的一个通过/失败结果。

我想创建某种动态系统,其中我放置在特定文件夹中的每个文件都通过相同的单元测试运行。因此,如果文件夹中有25个文件,则测试运行25次,单元测试结果报告运行了25个测试,并且每个测试都包含单独的通过/失败。

有什么想法可以在c#单元测试中完成吗?或者用nunit测试?

谢谢!我希望这不是一个重复的问题。我环顾四周,但找不到任何东西。

4 个答案:

答案 0 :(得分:10)

听起来您需要的是参数化测试用例:请参阅http://www.nunit.org/index.php?p=testCaseSource&r=2.5

所以:

[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));
    }
}

[TestCaseSource]属性告诉NUnit从字符串数组中获取字符串参数的值。

但是,这种方法需要文件名的静态常量。如果您更愿意使用程序化方法从数据库中读取文件,或者尝试像这样的工厂类:

[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);
            }
        }
    }
}

TestCaseData类生成“测试用例”,其期望可以通过流畅的界面设置。

答案 1 :(得分:5)

参数化测试(http://www.nunit.org/index.php?p=parameterizedTests&r=2.5)可能对您有用,具体取决于您的操作方式。

您可以使用的TestcaseAttribute示例,或者还有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 );
}

您可以获得编写和维护一个测试的优势,但结果适用于每种情况。

答案 2 :(得分:3)

另一种选择是使用T4模板根据目录中的文件数为您动态生成测试。将此“.tt”文件添加到您的单元测试项目中。

现在每当你按下visual studio中的“在解决方案中运行所有测试”按钮之前进行构建时,它应该为单元测试中文件名的目录中的所有文件生成单元测试。然后你的测试运行应该有一个很好的列表,列出它测试的所有文件及其状态。

<#@ 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
        }
        <# } #>
    }
}

答案 3 :(得分:0)

首先,测试取决于外部资源,如磁盘上的文件,不是严格的单元测试(意见)。

您正在寻找的是数据驱动的测试方法,然后您应该寻找支持它的工具,例如MSTestMBunit。 (点击链接获取更多信息)。

然后你可以这样做(使用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".
  }
}