6

我有一个使用 XML 文件并根据输入生成文本输出的类。输入和输出都相当复杂,输出还可以包含输入中没有的内容:例如,包括时间戳和不受输入控制的实时数据的结果 - 换句话说:该类不是纯粹的输入-输出转型。

我想使用 JUnit 测试生成的文本输出。由于生成的文本可以根据输入以多种不同的方式变化,我希望能够在每个测试中将输出的特定部分与某种模板进行匹配。每个模板都应该允许一些简单的文本替换以及文本中不应匹配的范围

问题是这样的框架是否已经存在?

一种非常低级的可能性是使用一些花哨的正则表达式来匹配文本,但我认为这些对于我们的使用来说有点太有限了,因为你在正则表达式中没有足够的上下文......

编辑:两条评论:

  • 该类的功能之一是能够根据输入进行某些简单类型的数据聚合和计算(例如总和)。我想测试这个,而不测试生成的文本输出的其余部分。
  • 我希望可以对现有代码库进行更改,但这是我真的不想重构的大量遗留代码。因此,不可能引入模拟服务或测试较小的部分。
4

5 回答 5

2

也许这表明您需要在较低级别进行测试?即测试贡献的组件而不是整体输出。我希望您可以安排您的代码/测试,以便您可以提供一组不可变的输入(可能在必要时使用模拟),因此输出不会改变。

一些高级测试会很有用(以确认结果集成),您也许可以通过简单的字符串比较来做到这一点(只是为了确认东西是否被正确集成),但我认为应该把努力放在更细化的地方等级。

否则我怀疑你可能想要一个类似 diff 的工具,而这个库看起来可能很有用。

于 2013-01-10T11:53:27.783 回答
1

我会使用Groovy编写单元测试,因为这是 Groovy 的优势之一,请参阅

但是 Groovy 在处理 XML 方面也非常出色,请参阅

总结一些 XML 属性的小例子:

// multiline string, very complex XML content :-)
def input = '''\
<list>
    <summand value='13' time='10:40' text='Compare me!'/>
    <summand value='1' />
    <summand value='4' />
    <summand value='2' />
    <summand value='7' />
</list>'''

// reading XML via XmlSlurper
def list = new XmlSlurper().parseText(input)

// Prints 13
println list.summand[0].@value

// collect all summand values, prints 27
println list.summand.collect { it.@value.toInteger() }.sum()

您可以在MEAP Making Java Groovy中找到一个很好的测试教程,或者查看这个演示文稿

Groovy 也有模板支持。但是通过 XML 支持,很容易只比较某些属性而不是整个标签内容来跳过一些属性,比如你提到的时间戳。因此,您无需比较模板。例如,将此源添加到上面的脚本中:

// compare the first summand tag, skipping the time attribute
assert [list.summand[0].@value.toInteger(), list.summand[0].@text] == [13, 'Compare me!']

要学习 Groovy,我推荐Groovy Koans。另请参阅将 Groovy 测试添加到 Maven Java 项目

更新:
我不会将 XML 相互比较,而是对我的答案中描述的单个值进行单元测试。但如果你走完整的路,我会使用以下方法:

于 2013-01-20T13:00:44.347 回答
0

我认为我们对您需要实现的目标、消息的输出格式等信息太少了。但是我认为,既然我们在谈论测试,那么您确实对要测试的数据有大量信息你的代码库反对。

如果该类产生稳定的输出(即对于相同的输入,它始终产生相同的输出),那么您可能想要为要测试的给定数据集创建某种模板(例如使用Velocity) . 您也可以将输入到您的类中包含的数据应用到您的模板中。根据测试类的输出,您可以测试它是否包含模板生成的内容,或者(如果这不可行)对模板生成的内容使用 DIFF 工具。

如果您的输出是人类可读的文本,那么也许使用 Lucene 对其进行索引并搜索匹配项可能是您的解决方案?如果不是,那么仍然使用模糊搜索算法匹配模板结果甚至预定义输出可能是一个可行的选择。

您需要回答的一个问题是重构底层代码库是否(尤其是从长远来看)不是一项更便宜的任务。

您是否还考虑过测试底层代码的行为(使用Mockito)而不是测试其输出?我想这会更难,因为它是您正在处理的遗留代码,但也许它是可行的?您还可以使用PowerMock来强化自己,它允许模拟静态方法和其他魔法——通常在遗留代码中很方便。

于 2013-01-19T16:36:49.033 回答
0

我建议使用将输出 XML 转换为对象树的工具来解析输出 XML。然后,您可以评估对象树而不是 XML 字符串,并仅在您感兴趣的那些部分上编写您的断言语句。它还允许您进行字符串工具无法进行的测试,例如计算元素的数量等。

如果您有输出的 XSD,则可以使用例如 XMLBeans 或 JABX。如果您没有 XSD,您可以编写基于 SAX 的自动机或使用 XPath 表达式来选择 XML 树的某些部分。

于 2013-01-19T17:00:55.480 回答
-1

您可以使用 Mockito 和 PowerMock 来测试代码的分离部分,PowerMock 让您可以做任何您想做的事情,包括用模拟对象替换新实例创建、模拟/替换静态、私有方法和类,简而言之,一切。这种组合应该足够强大,可以测试代码的不同部分,而无需测试整个代码。

我认为当您通过具有许多不同部分的不受控制的流程运行 1mb 文件时,您不能调用单元测试,您无法真正知道发生了什么以及发生故障时发生的位置。

于 2013-01-19T19:29:40.020 回答