在自己的单元测试中断言函数输出?

时间:2009-12-02 16:36:40

标签: unit-testing tdd

如果那个标题没有意义(我期待=),这就是我要问的问题:

我有一个名为ParseFile()的函数。它接受一个字符串作为参数,一个DataTable作为返回值。

我想对这个功能进行单元测试。我首先编写函数,运行它,获取输出,将其序列化为XML,将其保存为预期输出,然后编写单元测试以调用函数并对该反序列化数据进行断言,这是错误的吗?

我意识到这有助于我的发展,如果我们得到新的输入,我们可能以前可能没有看到,并且必须更改解析功能来处理它 - 运行我的测试现在断言我没有打破任何当前工作文件。真棒...

..但在这种情况下,格式永远不会改变并且是标准的。做我说的话完全没用了吗?如果是,那么如何测试这个功能呢?

哎呀,如果我说的话仍然是个好主意 - 你怎么会做真正的TDD风格并先编写测试 ?没有繁琐地为文件中的每个预期字段编写Assert calls()?我还没有完全处于完全TDD'模式' - 但我正试图到达那里......而且就像这些情况我有时想知道你是如何首先为它编写测试的,当预期的输出是一个数据集时示例...

谢谢

6 个答案:

答案 0 :(得分:4)

没错,但不是TDD。

话虽这么说,我想警告你在XML字符串上断言:当XML大小足够大时出现问题时,你最终会手动比较两个XML字符串,错误,直观。

去过那里,做到了。我记得在这种情况下,将XML复制到两个文件中,修改它以使每行有一个属性,并将这两个文件与diff进行比较。我说我下次尝试使用XPath和/或XQuery断言XML。

另外,你的函数不是做了太多事情:解析字符串生成XML?您可能需要考虑将其分开。

  

你怎么会做真正的TDD   风格并先写下测试?

如果你真的想使用TDD并保留一个函数,那么你可以从一个测试开始:你的XML输出应该是什么样的空字符串?这是你的第一次测试。一旦传递,使用带有简单元素的字符串重新启动,编写测试,使其通过,并采用更复杂的字符串。泡沫,冲洗,重复。

答案 1 :(得分:3)

这似乎更像是黑盒测试,而不是单元测试。但是,如果您确定生成的数据集是正确的,那么我没有看到您执行此操作的方式存在问题。您确保数据集在将来不会发生变化,我认为这是一个很好的测试,但可能不一定是单元测试

答案 2 :(得分:3)

我过去曾经使用过这样的测试 - 它们通常非常有用。

他们完全不是TDD。我发现当我的代码在没有TDD的情况下更好地构建时,我会编写这种测试:胶水代码。你特别看到这个数据摘录(又名“查询数据库中的这个(现有的)数据,用这种方式格式化,然后发送给客户端。”)你可以TDD字段格式化程序或其他实用程序对象,但最终所有重要的对于这种代码,如果您为给定(大)输入生成给定(大)输出。将代码从里到外转为引入测试接缝是不值得的麻烦。

通过这种测试,您确实获得了单元测试套件最重要的优点:如果您更改了共享的基础功能,并且它会破坏功能,那么您的测试将变为红色。

有些人会说这不是单元测试,因为它不是孤立的。我不在乎。这种区别对我没有任何帮助。这个测试让我确信系统正在按预期工作。这让我可以毫不畏惧地对代码库进行更改。

答案 3 :(得分:2)

这取决于你编写测试的原因。

从测试驱动开发的角度来看,您描述的过程是错误的。从质量保证的角度来看,它非常有意义,因为它为您提供了一个回归测试套件,可以在您前进时作为安全网。

使用TDD开发此类方法的关键是将它们分成更小的块(单元)并单独测试每个块。如果您可以设法将其拆分为许多较小的块,那么它通常会产生更灵活且可重复使用的API,而不是使用单个方法来进行某些输入和输出以及该方法背后的大量工作。

你如何拆分这种方法?

开始思考如何将其组织成私有帮助方法。然后考虑一下(或所有)这些辅助方法是否可以设想由一个对象本身来表示。在这个意义上,诸如策略抽象工厂之类的设计模式可能会非常有用。

不是使用具有大量内部逻辑的粗粒度API,而是使用具有大量公共但可组合逻辑的细粒度API。

答案 4 :(得分:2)

通常我会尝试远离测试“广泛”的功能。我更喜欢测试更细粒度的函数。我假设您的ParseFile()方法使用了几种实用方法,它们本身使用其他实用方法。这些是我尝试测试的方法。通常,任何类似的输入都由几个不同的数据组成。您是否可以通过ParseFile()方法和正在解析的数据进行测试而不是尝试测试整个文件是否被正确解析,而是将其分解为几个较小的测试,这些测试在聚合时会给您相同的信心?

我更喜欢这种方法的个人理由是,如果我需要修改任何解析代码并且测试失败,我有一个更快的路径来找到失败的来源,而不是“ParseFile()没有返回预期的结果“。 :)

答案 5 :(得分:1)

您不应将对象的序列化形式与测试进行比较。这太具体了。你应该只测试界面。

您应该测试DataTable对象的特定属性,例如,它有四行,五列,并且该单元[1,2]包含字符串“Fish”。