C# 实现XML文件转换器时的单元测试

C# 实现XML文件转换器时的单元测试,c#,xml,unit-testing,csv,C#,Xml,Unit Testing,Csv,我正在编写一个简单的文件转换器,它将接受一个XML文件并将其转换为CSV,反之亦然 我已经实现了两个类,XMLtoCSV和CSVtoXML,它们都实现了一个Convert方法,该方法接受输入文件路径和过滤文本,并通过给定的过滤器过滤XML,然后执行转换。(例如,如果XML包含员工详细信息,我们可能希望对其进行过滤,以便仅检索某个部门的员工并将其转换为CSV文件) 我有一个单元测试来测试这个转换方法。在其中,我指定输入文件路径和过滤器字符串,调用Convert函数并断言布尔结果,但我还需要测试过滤

我正在编写一个简单的文件转换器,它将接受一个XML文件并将其转换为CSV,反之亦然

我已经实现了两个类,XMLtoCSV和CSVtoXML,它们都实现了一个Convert方法,该方法接受输入文件路径和过滤文本,并通过给定的过滤器过滤XML,然后执行转换。(例如,如果XML包含员工详细信息,我们可能希望对其进行过滤,以便仅检索某个部门的员工并将其转换为CSV文件)

我有一个单元测试来测试这个转换方法。在其中,我指定输入文件路径和过滤器字符串,调用Convert函数并断言布尔结果,但我还需要测试过滤是否有效,转换是否已完成

我的问题是,您真的需要访问文件IO并通过单元测试进行过滤和转换吗?这不是集成测试吗?如果不是,那么在不实际转换文件并返回结果的情况下,我如何断言过滤已起作用?我考虑过不使用Convert方法,但这并不一定证明我的Convert方法工作正常

欢迎提供任何帮助/建议


谢谢

我建议您在类中使用流,在应用程序中传递文件流,在单元测试中传递“假”或StringStream。这将使您更加灵活,以防您决定从WebService或任何其他方式获取此xml—您只需要传递一个流,而不是文件路径。

我建议您在类中使用流,在应用程序中传递文件流,并在单元测试中传递“假”或StringStream。这将使您更加灵活,以防您决定从WebService或任何其他方式获取此xml—您只需要传递一个流,而不是文件路径

我的问题是,您真的需要访问文件IO并执行以下操作吗 通过单元测试进行过滤和转换?这不是整合吗 测试

准确地说-在本例中,您正在测试3件事情-文件IO系统、实际文件内容和
Convert
方法本身

我认为您需要重新构造代码,使其更易于进行单元测试(这不是对代码的批评!)。考虑您对<代码>转换方法的定义:

在其中,我指定了输入文件路径和过滤器字符串

因此,您的
Convert
方法实际上是做两件事——打开/读取文件,以及转换内容。您需要改变周围的情况,以便Convert方法只做一件事——具体地说,执行字符串(或者实际上是流)的转换,而不必参考它的来源

通过这种方式,您可以通过向
Convert
方法提供您在单元测试中定义的字符串来正确测试该方法-一个测试具有已知的良好数据,另一个测试具有已知的不良数据

e、 g

当然,在你的
Convert
方法中,你正在做各种各样的神秘和奇妙的事情,这时你可以看看这个方法,看看你是否可以把它分成几个内部方法,这些方法的功能可能由不同的类提供,您可以将其作为依赖项提供给
转换器
类,然后可以对其进行单独测试

通过这样做,您将能够测试converter方法的两个功能,并且您将能够开始使用Mock,以便您也可以测试它的功能行为-例如确保
frobber
只调用一次,并且总是在
gibber
之前调用,而且
gibber
总是调用
munger
,等等

奖金 但是等等,还有更多!!!!1!! - 一旦您的转换器类/方法被这样安排,您会突然发现您现在可以实现一个XML到制表符分隔符,或者XML到JSON,或者XML到????只需编写相关组件并将其插入转换器类。松耦合FTW

e、 g(这里我只是在想象转换函数的核心是如何工作的)

当然,我不是想告诉您如何编写代码,但是上面的类对于单元测试和功能测试来说都是一个非常可测试的类,因为您可以根据需要混合和匹配mock、stub和real

我的问题是,您真的需要访问文件IO并执行以下操作吗 通过单元测试进行过滤和转换?这不是整合吗 测试

准确地说-在本例中,您正在测试3件事情-文件IO系统、实际文件内容和
Convert
方法本身

我认为您需要重新构造代码,使其更易于进行单元测试(这不是对代码的批评!)。考虑您对<代码>转换方法的定义:

在其中,我指定了输入文件路径和过滤器字符串

因此,您的
Convert
方法实际上是做两件事——打开/读取文件,以及转换内容。您需要改变周围的情况,以便Convert方法只做一件事——具体地说,执行字符串(或者实际上是流)的转换,而不必参考它的来源

通过这种方式,您可以通过向
Convert
方法提供您在单元测试中定义的字符串来正确测试该方法-一个测试具有已知的良好数据,另一个测试具有已知的不良数据

e、 g

当然,在你的
Convert
方法中,你正在做各种各样的神秘和奇妙的事情,这时你可以看看这个方法,看看你是否可以把它分成几个内部方法,这些方法的功能可能由不同的类提供,您可以将其作为依赖项提供给
转换器
类,然后可以对其进行单独测试

通过这样做,你将
void Convert_WithGoodInput_ReturnsTrue()
{
   var input="this is a piece of data I know is good and should pass";
   var sut = new Converter(); //or whatever it's called :)
   bool actual = sut.Convert(input);
   Assert.AreEqual(true,actual,"Convert failed to convert good data...");
}

void Convert_WithBadInput_ReturnsFalse()
{
   var input="this is a piece of data I know is BAD and should Fail. Bad Data! Bad!";
   var sut = new Converter(); //or whatever it's called :)
   bool actual = sut.Convert(input);
   Assert.AreEqual(false,actual,"Convert failed to complain about bad data...");
}
public class Converter
{
   public Converter(ISourceReader reader, IValidator validator, IFilter filter,IOutputformatter formatter)
   {
      //boring saving of dependencies to local privates here...
   }

   public bool Convert(string data,string filter)
   {
       if (!validator.Validate(data)) return false;
       var filtered = filter.Filter(data); 
       var raw = reader.Tokenise(filtered);
       var result = formatter.Format(raw);
       //and so on
       return true; //or whatever...
   }    
}