我正在编写一个简单的文件转换器,它将获取XML文件并将其转换为CSV,反之亦然。
我已经实现了两个类,XMLtoCSV和CSVtoXML,并且都实现了一个Convert方法,它接受输入文件路径和过滤文本,并通过给定的过滤器过滤XML并执行转换。 (例如,如果XML包含员工详细信息,我们可能希望对其进行过滤,以便仅检索某个部门的员工并将其转换为CSV文件)。
我有一个测试这个Convert方法的单元测试。在其中我指定输入文件路径和过滤器字符串并调用转换函数并断言布尔结果,但我还需要测试过滤是否有效并且转换是否已完成。
我的问题是你真的需要访问文件IO并通过单元测试进行过滤和转换吗?这不是集成测试吗?如果没有那么我如何断言过滤是否有效而没有实际转换文件并返回结果?我想过Moq'ing Convert方法,但这并不一定能证明我的Convert方法工作正常。
感谢任何帮助/建议。
由于
答案 0 :(得分:4)
我建议你在类中使用流并在应用程序中传递文件流,例如在单元测试中传递“假”或StringStream。这将使您更灵活,以防您决定从WebService或任何其他方式获取此xml - 您只需要传递流,而不是文件路径。
答案 1 :(得分:2)
我的问题是你真的需要访问文件IO吗? 通过单元测试进行过滤和转换?这不是整合 测试
准确地说 - 在这种情况下,您正在测试3件事 - 文件IO系统,实际文件内容,和 Convert
方法本身。
我认为您需要考虑重构代码,使其更适合单元测试(这不是对代码的批评!)。考虑一下Convert
方法的定义:
在其中我指定输入文件路径和过滤字符串
因此,您的Convert
方法实际上正在执行两个事情 - 打开/读取文件,以及转换内容。你需要改变一些东西,以便Convert方法只做一件事 - 具体来说,执行字符串(或实际上是一个流)的转换,而不需要引用它来自哪里。
通过这种方式,您可以通过为单元测试中自己定义的字符串提供Convert
方法来正确测试{ - 1}方法 - 一个测试具有已知的良好数据,另一个测试已知糟糕的数据。
e.g。
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...");
}
当然在你的Convert
方法中,你正在做各种神秘而美妙的事情,此时你可能会看看那个方法,看看是否可以把它分成几个内部方法,功能其中可能由单独的类提供,您可以将它们作为依赖项提供给Converter
类,而这些类又可以单独测试。
通过执行此操作,您将能够测试转换器方法的功能,和您将能够开始使用Mocks,以便您可以测试功能行为< / em>也是如此 - 例如确保frobber
只被调用一次,并始终在gibber
之前调用,而gibber
始终调用munger
,等
但等等,还有更多!!!! 1 !! - 一旦你的Converter类/方法像这样安排,你会突然发现你现在可以实现一个XML到Tab分隔,或XML到JSON,或XML到????只需编写相关组件并将其插入Converter类即可。松耦合FTW!
例如(在这里我只是想象你的转换函数的内容是如何工作的)
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...
}
}
当然我并不是想告诉你如何编写你的代码,但上面的单元和功能测试都是一个非常可测试的类,因为你可以根据你喜欢的方式混合和匹配Mocks,Stubs和Reals。 / p>