【问题标题】:C# Unit Test Design Issue: How to reduce redundancy in unit test writing?C#单元测试设计问题:如何减少单元测试编写中的冗余?
【发布时间】:2011-10-14 05:38:49
【问题描述】:

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

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

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

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

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

任何想法如何或是否可以在 c# 单元测试中完成?还是使用 nunit 测试?

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

【问题讨论】:

  • 有些人会争辩说,涉及 IO(在这种情况下操作文件系统)的测试不是单元测试。另一种方法是将 IO 操作表示为可注入的依赖项。然而,大多数 System.IO 类型(当然还有静态)并不适合这种情况。我使用的一种方法是创建普通方法转发类型和相应接口的代理程序集。这允许您不测试这个瘦代理层,而您的逻辑层完全单元测试。 Microsoft Moles 有效地动态执行此操作,但这仍然是 WIP。

标签: c# .net unit-testing nunit


【解决方案1】:

听起来你需要的是一个参数化的测试用例:见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 从字符串数组中获取字符串参数的值。

然而,这种方法需要 static 常量作为文件名。如果您希望使用一种从数据库或类似数据库中读取文件的编程方法,请尝试像这样的工厂类:

[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 类生成“测试用例”,这些用例具有可以通过流畅界面设置的期望。

【讨论】:

  • 这也是一个非常棒的解决方案。谢谢杰里米。
【解决方案2】:

参数化测试 (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 );
}

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

【讨论】:

    【解决方案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
            }
            <# } #>
        }
    }
    

    【讨论】:

    • 这是很棒的东西!直到现在我才知道这个功能,所以我真的很高兴我终于在 stackoverflow 上问了一个问题! :)
    • 感谢大家为我的问题提供宝贵意见!
    【解决方案4】:

    首先,依赖外部资源(如磁盘上的文件)进行测试并不是严格意义上的单元测试(观点)。

    您正在寻找的是一种数据驱动的测试方法,然后您应该寻找支持它的工具,例如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".
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-03
      • 2019-01-28
      • 1970-01-01
      相关资源
      最近更新 更多