我是TDD的新手,我发现RegExp非常特殊。是否有任何特殊的单元测试方法,或者我可以将它们视为常规功能?
答案 0 :(得分:83)
你应该总是测试你的regexen,就像任何其他代码块一样。它们是一个最简单的函数,它接受一个字符串并返回一个bool,或者返回一个值数组。
以下是关于为regexen设计单元测试时要考虑什么的一些建议。这些并不是单元测试设计的硬性和快速处方,而是一些塑造您思路的指导方针。与往常一样,将测试需求与故障成本进行权衡,并与实施所有测试所需的时间进行权衡。 (我发现'实施'测试很容易!: - ])
要考虑的要点:
对于返回列表的正则表达式,还要记住:
(?<name> thing1 ( thing2) )
) - 根据您正在使用的正则表达式引擎,此行为可能会有所不同。如果您使用任何高级功能,例如非回溯组,请确保您完全了解该功能的工作原理,并使用上述指南,构建适用于每个功能的示例字符串。
根据您的正则表达式库实现,捕获组的方式也可能不同。 Perl 5有一个'open paren order'排序,C#部分除了命名组等等。确保尝试你的味道,确切地知道它的作用。
然后,将它们与您的其他单元测试集成在一起,可以放在自己的模块中,也可以放在包含正则表达式的模块旁边。对于特别讨厌的regexen,您可能会发现需要大量的测试来验证您使用的模式和所有功能是否正确。如果正则表达式构成了该方法正在进行的大量(或几乎所有)工作,我将使用上面的建议来设置输入以测试该函数而不是直接使用正则表达式。这样,如果以后你决定正则表达式不是要走的路,或者你想要分解,你可以捕获正则表达式提供的行为而不改变接口 - 即调用正则表达式的方法。
只要您真正了解正则表达式功能如何适用于您的正则表达式,您应该能够为它开发体面的测试用例。只要确保你真的,真的,真的了解这个功能是如何运作的!
答案 1 :(得分:11)
只需抛出一堆值,检查您是否得到了正确的结果(无论是匹配/不匹配还是特定的替换值等)。
重要的是,如果您有任何不满意的角落情况他们是否会工作,请在单元测试中捕获它们并在评论中解释为什么他们的工作。这样,想要更改正则表达式的其他人将能够检查角落案例是否仍然有效,并且它会给出一个提示,告诉他们如果它破坏了如何修复它。
答案 2 :(得分:9)
据推测,您的正则表达式包含在类的方法中。例如:
public bool ValidateEmailAddress( string emailAddr )
{
// Validate the email address using regular expression.
return RegExProvider.Match( this.ValidEmailRegEx, emailAddr );
}
您现在可以为此方法编写测试。我想关键是正则表达式是一个实现细节 - 您的测试需要测试接口,在这种情况下只是验证电子邮件方法。
答案 3 :(得分:3)
我会创建一组具有预期输出值的输入值,就像每个其他测试用例一样。
另外,我可以彻底推荐免费的Regex工具Expresso。 它是一个出色的正则表达式编辑器/调试器,它在过去让我度过了几天的痛苦。
答案 4 :(得分:2)
我总是像其他任何功能一样测试它们。确保它们符合您认为应该匹配的内容,并且它们与不应该匹配的内容不匹配。
答案 5 :(得分:2)
我无法相信没有人发布这个神奇的工具:
它可以让你测试你的正则表达式。你定义了一些包含它应该匹配的字符串的文本,以及它不应该匹配的字符串,如果它全部是绿色的,你就是好的。例如,这是我用来匹配slu :: http://refiddle.com/by/callum-locke/slug-matcher
的一个答案 6 :(得分:1)
我认为简单的输入输出测试就足够了。随着时间的推移和某些情况下你的正则表达式失败,不要忘记在修复时将这些情况添加到测试中。
答案 7 :(得分:1)
我喜欢针对相反的正则表达式测试正则表达式,我将针对可能的测试执行两者并确保交集为空。
答案 8 :(得分:1)
首先考虑编写测试,并且只编写通过每个测试所需的正则表达式。如果您需要扩展正则表达式,请通过添加失败测试来完成。
答案 9 :(得分:0)
在所选的单元测试库中使用固定装置,并遵循通常的TDD方法:
以下是供spock作为测试跑步者的样品夹具存根:
@Grab('org.spockframework:spock-core:1.3-groovy-2.5')
@GrabExclude('org.codehaus.groovy:groovy-nio')
@GrabExclude('org.codehaus.groovy:groovy-macro')
@GrabExclude('org.codehaus.groovy:groovy-sql')
@GrabExclude('org.codehaus.groovy:groovy-xml')
import spock.lang.Unroll
class RegexSpec extends spock.lang.Specification {
String REGEX = /[-+]?\d+(\.\d+)?([eE][-+]?\d+)?/
@Unroll
def 'matching example #example for case "#description" should yield #isMatchExpected'(String description, String example, Boolean isMatchExpected) {
expect:
isMatchExpected == (example ==~ REGEX)
where:
description | example || isMatchExpected
"empty string" | "" || false
"single non-digit" | "a" || false
"single digit" | "1" || true
"integer" | "123" || true
"integer, negative sign" | "-123" || true
"integer, positive sign" | "+123" || true
"float" | "123.12" || true
"float with exponent extension but no value" | "123.12e" || false
"float with exponent" | "123.12e12" || true
"float with uppercase exponent" | "123.12E12" || true
"float with non-integer exponent" | "123.12e12.12" || false
"float with exponent, positive sign" | "123.12e+12" || true
"float with exponent, negative sign" | "123.12e-12" || true
}
}
它可以像一个独立的常规脚本一样运行
groovy regex-test.groovy
免责声明:该摘录摘自我几周前写的一系列博客文章