是否应该对复杂的正则表达式进行单元测试?


34

我应该在应用程序中为复杂的正则表达式编写单元测试吗?

  • 一方面:它们易于测试,因为输入和输出格式通常很简单且定义明确,而且它们往往变得如此复杂,因此对它们的测试特别有价值。
  • 另一方面:它们本身很少是某个单元界面的一部分。最好只测试接口,然后以隐式测试正则表达式的方式进行操作。

编辑:

我同意布朗博士的意见,他在评论中指出这是内部组件单元测试的特例。

但是正则表达式作为内部组件具有一些特殊特征:

  1. 没有真正的单独模块,单行正则表达式可能非常复杂。
  2. 正则表达式将输入映射到输出而没有任何副作用,因此真正易于单独测试。

12
“它们本身很少是某个单元界面的一部分。” -如果您的班级中有很多有趣的代码埋在该接口下,请拆分您的班级。这是思考TESS如何改善设计的一个示例。
内森·库珀

3
以更笼统的方式回答同样的问题:应该对哪些内部组件进行单元测试?见programmers.stackexchange.com/questions/16732/...
布朗博士

有关Sorta的信息,请参见Regex101。他们有一节为您的regex编写单元测试。例如:regex101.com/r/tR3mJ2/2
大卫说请

3
免责声明-这个评论是我的愚见: 1首先我认为,复杂的正则表达式是纯粹的邪恶-又见blog.codinghorror.com/... 2 测试这样表达的真正价值在于,当你在一个大的数据库,真正的测试它们数据blog.codinghorror.com/testing-with-the-force 3我感到奇怪的是,这些测试并非完全是单元测试
Boris Treukhov,2016年

Answers:


101

除了测试教条主义,真正的问题是它是否为单元测试复杂的正则表达式提供价值。很显然,如果正则表达式足够复杂,它确实可以提供价值(不管正则表达式是否是公共接口的一部分),因为正则表达式允许您查找和重现错误并防止回归。


25
+1,但如果正则表达式是足够复杂的,这是一个问题,那么它很可能是有道理的,将其移动到适当的方式“包装”单位(isValidparsetryParse,或诸如此类的东西,恰恰取决于它如何被使用),所以客户端代码不必知道当前是否使用正则表达式实现。然后,包装器单元将进行详细的测试,而这些测试又不需要知道当前的实现。当然,这些测试实际上是在测试正则表达式,但是与实现无关。
鲁阿赫

1
reg ex是一个程序,尽管使用的是专用且非常简洁的语言。因此,测试适用于非平凡的表达式...并且肯定会测试调用该表达式的代码,这可能会隐式测试保留的代码。
keshlam '16

6
@ruakh好吧。正则表达式的包装器类的好处是,如果有必要,可以用普通代码巧妙地替换它。具有复杂输入/输出的代码应该始终进行单元测试,因为如果不这样做,则很难调试。如果需要参考文档以了解代码的作用,则应进行单元测试。如果它只是一个快速的1:1映射(如类型转换),那么就没有问题。正则表达式很快就超过了需要文档的要求。
Aaron3468 '16

4
@Lii:正则表达式不应该得到任何特殊待遇。regex在这种情况下是单位,因此我们对其进行单元测试。
JacquesB '16

1
@ruakh我正要为此写一个答案。我同意使用正则表达式是实现细节。重要的是,事物应该在应有的时候生效,而未能在应有的时候生效。测试的FooValidator输入和输出,然后您就不必担心它是如何完成的。++
RubberDuck

21

正则表达式可以是一个功能强大的工具,但即使对复杂的正则表达式进行很小的更改,它也不是您可以信赖的工具,它仍然可以正常工作。

因此,创建大量测试以记录应涵盖的案例。并创建许多测试,以记录如果失败用于验证的情况。

每当需要更改正则表达式时,都将新案例添加为测试,修改正则表达式并希望获得最佳效果。

如果我所在的组织通常不使用单元测试,我仍然会编写一个测试程序来测试我们要使用的任何正则表达式。如果需要的话,我什至会自己动手做,我的头发不再需要褪色。


3

正则表达式与应用程序的其余部分一起是代码。您应该测试代码总体上是否符合您的期望。这有几个目的:

  • 测试是可运行的文档。它清楚地演示了您需要代码执行的操作。如果经过测试,那很重要。
  • 将来的维护者可以确定,如果他们对其进行修改,则测试将确保行为不变。

由于将其他语言的代码嵌入到其他代码中还需要克服一个额外的障碍,因此您很可能应该特别注意这一点,以便维护。


1

简而言之,您应该测试您的应用程序。无论您是使用自动运行的正则表达式来测试正则表达式,还是作为一个更大的黑匣子的一部分来进行测试,还是仅是手工摆弄它,都是您要确保它正常工作的第二要务。

单元测试的主要优点是可以节省时间。他们使您可以现在或将来的任意时间对事物进行多次测试。如果有任何理由相信您的正则表达式将在任何时候进行重构,调整,获得更多约束等,那么是的,您可能需要对其进行一些回归测试,或者当您进行更改时,您必须经过一个小时的思考,对所有极端情况进行了思考,这样您才不会遇到麻烦。那样,或者您学会了忍受着自己的代码的恐惧,并且永远不要更改它。


3
我已经意识到的经验法则;如果我需要文档来编写和检查代码,则需要进行单元测试。它们为我省去了很多麻烦,捕获了空指针,没有类型和错误的输出。它们还使最终用户能够在不可避免的情况下以最小的努力修复代码以符合规范。
Aaron3468'6

-1

另一方面:它们本身很少是某个单元界面的一部分。最好只测试接口,然后以隐式测试正则表达式的方式进行操作。

我认为您可以自己回答。一个单元中的正则表达式很可能是实现细节。

用于测试SQL的内容可能也适用于正则表达式。当您更改一条SQL时,您可能需要手动通过某个SQL客户端运行它,以查看它是否产生了预期的效果。当我更改正则表达式时,我也会使用带有某些示例输入的正则表达式工具来查看其是否符合我的预期。

我发现有用的是在正则表达式附近添加了注释,并带有应匹配的文本示例。


当您更改一条SQL时,您可能会通过一些SQL客户端手动运行它,以查看它是否能达到您的期望。 ”但是,这种方式可以用另一种方式回答问题……如果我需要或认为对手动测试正则表达式,然后我应该对此进行单元测试。正是这就是要做出决定的棘手事情!

真的要看 您想要进行单元测试的是进行更改的能力。您多久更改一次特定的正则表达式?如果答案是经常的,那么一定要为此做一个测试。
克里斯蒂安(Christiaan)

8
在其他所有条件都相同的情况下,拥有自动化测试比“手动测试”更好。
罗伯特·哈维,

1
为什么不使用自动化测试正则表达式?
托尼·恩尼斯

1
它是方法的一部分,我想说的是,如果您已经测试过该方法,则无需专门测试正则表达式。但是,如果这样做,最好将正则表达式提取到单独测试的单独函数中。
克里斯蒂安(Christiaan)

-5

如果需要询问,答案是肯定的。

假设出现了一些FNG,并认为他可以“改善”您的正则表达式。现在,他是一名FNG,因此自然是个白痴。恰恰是那种在任何情况下都不应该触摸您的宝贵代码的人!但是也许他和PHB有关,所以您无能为力。

除非您知道PHB会拖延您的踢踢和尖叫,否则一切都会变坏时“也许会给这个家伙一些有关您如何使此混乱的指示”。因此,您记下在构建漂亮的表达力杰作时仔细考虑的所有案例。

既然已经将它们全部写下来,那么您拥有一套测试用例的方式就占了三分之二,因为-让我们面对现实-一旦构建了框架,正则表达式测试用例就非常容易运行。

因此,现在您有了一组边缘条件,替代方法和预期结果。就像所有这些敏捷的博客文章中所承诺的那样,突然之间,测试用例就是文档。您只是向FNG指出,如果他的“改进”没有通过现有的测试用例,那就不是很大的改进,不是吗?他提出的新测试用例在哪里,这些原始用例证明了原始代码的某些问题,由于该代码有效,因此他不需要进行修改!!!


3
什么是FNG?这对我来说似乎不是一个不好的答案,但是缺少FNG的定义(googlin所给出的结果不相关,所以也许这个答案只是因为FNG而被
否决了

1
我怀疑Google将您带到了正确的位置。;
奥斯丁·黑斯廷斯

除非您是绝对的编程天才,否则会有更多有经验的程序员考虑您对新手的看法。您可能要考虑变得更谦虚。
托尔比约恩Ravn的安徒生
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.