如何在单元测试中将文本与模板匹配

时间:2013-01-10 11:50:34

标签: java unit-testing junit4

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

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

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

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

编辑:两条评论:

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

5 个答案:

答案 0 :(得分:2)

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

一些高级测试会很有用(确认结果集成),你也许可以通过一个简单的字符串比较来做到这一点(只是为了确认正确整合的东西),但我认为应该把努力放在更细粒度的水平。

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

答案 1 :(得分: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找到有关测试的好教程,或者查看此presentation

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

// 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。另请参阅Adding Groovy Tests to a Maven Java Project

<强>更新
我不会将XML相互比较,而是将单个值单元测试为我的答案所描述的。但如果你走完全路,我会采用以下方法:

  • 从您的业务逻辑中获取XML
  • 删除临时(与Groovy不可比较的值)
  • 从GStringTemplateEngine生成模板(参见上面的链接),没有可比较的值
  • 通过http://xmlunit.sourceforge.net/来比较两个XML 您可以在页面末尾的Updating XML with XmlSlurper找到一个示例。

答案 2 :(得分:0)

我认为我们对你需要实现什么,消息的输出格式是什么等信息太少了。但是我认为既然我们正在谈论测试,那么你确实有关于你的数据的实质性信息想要测试你的代码库。

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

如果你的输出是一个人类可读的文本,那么可以用Lucene索引它,搜索匹配可能是你的解决方案吗?如果没有那么仍然匹配模板结果甚至预定义的输出与模糊搜索算法可能是一个可行的选择。

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

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

答案 3 :(得分:0)

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

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

答案 4 :(得分:-1)

您可以使用Mockito和PowerMock来测试代码的分离部分,PowerMock允许您执行任何您喜欢的操作,包括使用模拟对象替换新实例创建,模拟/替换静态,私有方法和类,简而言之,一切。这种组合应该足够强大,可以测试代码的各个部分,而无需测试整个代码。

当你通过一个包含许多不同部分的不受控制的流程运行1mb文件时,我认为你不能调用单元测试,你不能真正知道发生了什么以及在发生故障时它发生了什么。