单元测试用于比较NUnit中的文本文件

时间:2008-09-26 21:34:06

标签: unit-testing nunit diff text-files

我有一个处理2个xml文件并生成文本文件的类。

我想编写一堆单元/集成测试,可以单独传递或失败,以便执行以下操作:

  1. 对于输入A和B,生成输出。
  2. 将生成的文件的内容与预期输出的内容进行比较
  3. 当实际内容与预期内容不同时,请失败并显示一些有用的有关差异的信息。
  4. 以下是该课程的原型以及我在单元测试中的第一次尝试。

    我应该使用哪种模式进行此类测试,还是人们倾向于编写数以万计的TestX()函数?

    有没有更好的方法来哄骗NUnit的文本文件差异?我应该嵌入文本文件差异算法吗?


    class ReportGenerator
    {
        string Generate(string inputPathA, string inputPathB)
        {
            //do stuff
        }
    }
    

    [TextFixture]
    public class ReportGeneratorTests
    {
         static Diff(string pathToExpectedResult, string pathToActualResult)
         {
             using (StreamReader rs1 = File.OpenText(pathToExpectedResult))
             {
                 using (StreamReader rs2 = File.OpenText(pathToActualResult))
                 {
                     string actualContents = rs2.ReadToEnd();
                     string expectedContents = rs1.ReadToEnd();                  
    
                     //this works, but the output could be a LOT more useful.
                     Assert.AreEqual(expectedContents, actualContents);
                 }
             }
         }
    
         static TestGenerate(string pathToInputA, string pathToInputB, string pathToExpectedResult)
         {
              ReportGenerator obj = new ReportGenerator();
              string pathToResult = obj.Generate(pathToInputA, pathToInputB);
              Diff(pathToExpectedResult, pathToResult);
         }
    
         [Test]
         public void TestX()
         {
              TestGenerate("x1.xml", "x2.xml", "x-expected.txt");
         }
    
         [Test]
         public void TestY()
         {
              TestGenerate("y1.xml", "y2.xml", "y-expected.txt");
         }
    
         //etc...
    }
    

    更新

    我对测试diff功能不感兴趣。我只是想用它来产生更多可读的失败。

5 个答案:

答案 0 :(得分:5)

对于使用不同数据的多个测试,请使用NUnit RowTest扩展名:

using NUnit.Framework.Extensions;

[RowTest]
[Row("x1.xml", "x2.xml", "x-expected.xml")]
[Row("y1.xml", "y2.xml", "y-expected.xml")]
public void TestGenerate(string pathToInputA, string pathToInputB, string pathToExpectedResult)
 {
      ReportGenerator obj = new ReportGenerator();
      string pathToResult = obj.Generate(pathToInputA, pathToInputB);
      Diff(pathToExpectedResult, pathToResult);
 }

答案 1 :(得分:2)

你可能要求对“黄金”数据进行测试。我不知道世界范围内是否有这种测试的具体术语,但这就是我们这样做的方式。

创建基础夹具类。它基本上有“void DoTest(string fileName)”,它将特定文件读入内存,执行抽象转换方法“string Transform(string text)”,然后从同一个地方读取fileName.gold,并将转换后的文本与预期的文本进行比较。如果内容不同,则抛出异常。抛出的异常包含第一个差异的行号以及预期行和实际行的文本。由于文本是稳定的,这通常足以立即发现问题。一定要用“Expected:”和“Actual:”来标记行,否则你将永远猜测在查看测试结果时的哪一行。

然后,您将拥有特定的测试装置,您可以在其中实现正确工作的Transform方法,然后进行如下所示的测试:

[Test] public void TestX() { DoTest("X"); }
[Test] public void TestY() { DoTest("Y"); }

失败测试的名称会立即告诉您什么是坏的。当然,您可以使用行测试对类似的测试进行分组。单独测试也有助于在许多情况下,例如忽略测试,向同事传达测试等等。创建一个会在一秒钟内为您创建测试的片段并不是什么大不了的事,您将花费更多时间来准备数据。

然后你还需要一些测试数据以及基础夹具找到它的方法,一定要为项目设置相关的规则。如果测试失败,则将实际输出转储到黄金附近的文件中,并在测试通过时将其删除。这样您就可以在需要时使用diff工具。当没有找到黄金数据时,测试失败并显示相应的消息,但无论如何都会写入实际输出,因此您可以检查它是否正确并将其复制为“黄金”。

答案 2 :(得分:0)

您可以自己解析两个输入流,保留行和列的计数并比较内容,而不是调用.AreEqual。一旦找到差异,就可以生成类似......

的消息
  

第32行第12列 - 预期'y'时找到'x'

您可以选择通过显示多行输出来增强它

  

第32行第12列的差异,显示第一个差异
  A =这是t x st   B =这是一个t e sts

注意,作为一项规则,我通常只通过我的代码生成您拥有的两个流中的一个。另一个我从测试/文本文件中获取,通过眼睛或其他方法验证所包含的数据是否正确!

答案 3 :(得分:0)

我可能会写一个包含循环的单元测试。在循环内部,我会读取2个xml文件和一个diff文件,然后将xml文件进行区分(不将其写入磁盘)并将其与从磁盘读取的diff文件进行比较。这些文件将被编号,例如a1.xml,b1.xml,diff1.txt; a2.xml,b2.xml,diff2.txt; a3.xml,b3.xml,diff3.txt等,当循环找不到下一个数字时循环停止。

然后,您只需添加新的文本文件即可编写新测试。

答案 4 :(得分:0)

我可能会使用XmlReader迭代文件并进行比较。当我遇到差异时,我会在文件不同的位置显示XPath。

PS:但实际上,我只需要将整个文件简单地读取到一个字符串并比较两个字符串就足够了。对于报告,足以看到测试失败。然后,当我进行调试时,我通常使用Araxis Merge对文件进行区分,以查看我究竟在哪里遇到问题。