我正在编写一个简单的文件转换器,它将获取XML文件并将其转换为CSV,反之亦然。
我已经实现了 2 个类,XMLtoCSV 和 CSVtoXML,并且都实现了一个转换方法,该方法采用输入文件路径和过滤器文本,并通过给定过滤器过滤 XML 并执行转换。(例如,如果XML包含员工详细信息,我们可能希望对其进行过滤,以便仅检索来自某个部门的员工并将其转换为CSV文件)。
我有一个测试此转换方法的单元测试。在其中,我指定了输入文件路径和过滤器字符串,并调用 Convert 函数并断言布尔结果,但我还需要测试过滤是否有效并且转换是否已完成。
我的问题是,您真的需要访问文件 IO 并通过单元测试进行过滤和转换吗?这不是集成测试吗?如果不是,那么我如何在不实际转换文件并返回结果的情况下断言过滤已经有效?我想过对转换方法进行 Moq'ing,但这并不一定证明我的转换方法工作正常。
任何帮助/建议不胜感激。
谢谢
我建议您在类中使用流,并在应用程序中传递文件流,并在单元测试中传递"fake"或StringStream。这将使您更加灵活,以防您决定从 WebService 或任何其他方式获取此 xml - 您只需要传递流,而不是文件路径。
我的问题是,你真的需要访问文件IO并做 通过单元测试进行过滤和转换?这不是集成吗 测试?
确切地说 - 在这种情况下,您正在测试 3 件事 - 文件 IO 系统、实际文件内容和 Convert
方法本身。
我认为您需要考虑重组您的代码以使其更适合单元测试(这不是对您的代码的批评!考虑一下您对Convert
方法的定义:
在其中我指定输入文件路径和过滤器字符串
因此,您的Convert
方法实际上是做两件事 - 打开/读取文件和转换内容。您需要更改内容,以便 Convert 方法仅执行一件事 - 具体来说,执行字符串(或实际上是流)的转换,而无需引用它的来源。
这样,您可以通过向 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...");
}
当然,在你的Convert
方法中,你正在做各种晦涩而奇妙的事情,在这一点上,你可以看看该方法,看看是否可以把它分成几个内部方法,其功能可能由单独的类提供,你作为Converter
类的依赖项提供, 反过来,所有这些都可以单独测试。
通过这样做,您将能够测试转换器方法的功能,并且您将能够开始使用 Mocks,以便您也可以测试它的功能行为 - 例如确保frobber
只调用一次,并且始终在gibber
之前, 并且gibber
总是称munger
,等等。
奖金
但是等等,还有更多!!!1!!- 一旦你的转换器类/方法像这样排列,你会突然发现你现在可以实现一个XML到制表符分隔,或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...
}
}
当然,我并不是想告诉你如何编写代码,但上面是一个非常可测试的类,用于单元测试和功能测试,因为您可以根据需要混合和匹配模拟、存根和真实。