随机数据在unit testing?
我有一个同事为对象填写随机数据的unit testing。 他的理由是它提供了更广泛的testing,因为它会testing很多不同的值,而正常的testing只使用一个静态值。
我给了他很多不同的理由,主要是:
- 随机值意味着testing不是真正可重复的(这也意味着,如果testing可以随机失败,它可以在构build服务器上这样做,并打破构build)
- 如果它是一个随机值并且testing失败,我们需要a)修复这个对象,并且b)强迫我们每次testing这个值,所以我们知道它是有效的,但是因为它是随机的,所以我们不知道这个值是什么
另一位同事补充说:
- 如果我正在testing一个exception,那么随机值将不能确保testing以预期的状态结束
- 随机数据用于清除系统和加载testing,而不是unit testing
其他人可以添加额外的理由,我可以给他让他停止这样做吗?
(或者,这是写一个unit testing的可接受的方法,我和我的另一个同事是错的?)
有一个妥协。 你的同事实际上是在做某事,但我认为他做错了。 我不确定完全随机testing是非常有用的,但肯定不是无效的。
程序(或单元)规范是一个假设,存在一些符合它的程序。 程序本身就是这个假设的证据。 unit testing应该是提供反证据以反驳程序按规范工作的尝试。
现在,你可以手工编写unit testing,但它确实是一个机械的任务。 它可以自动化。 所有你需要做的就是编写规范,一台机器可以生成大量的unit testing,试图破坏你的代码。
我不知道你在用什么语言,但是看到这里:
Java http://functionaljava.org/
Scala(或Java) http://github.com/rickynils/scalacheck
Haskell http://www.cs.chalmers.se/~rjmh/QuickCheck/
.NET: http : //blogs.msdn.com/dsyme/archive/2008/08/09/fscheck-0-2.aspx
这些工具将把你的格式规范作为input,并自动生成任意数量的unit testing,并自动生成数据。 他们使用“缩小”的策略(你可以调整)find最简单的testing用例来破坏你的代码,并确保它能很好地覆盖边缘情况。
快乐的testing!
这种testing称为猴testing 。 如果做得对,它可以从真正黑暗的angular落吸出虫子。
为了解决您对可重复性的担忧:正确的方法是logging失败的testing条目,生成一个unit testing,探测整个特定错误的家族 ; 并在unit testing中包含引起初始故障的一个特定input(来自随机数据)。
在这里有一个中途的房子,有一些使用,这是一个常数种子你的PRNG。 这使您可以生成可重复的“随机”数据。
就我个人而言,我认为有些地方(恒定的)随机数据在testing中是有用的 – 在你认为你已经完成了所有仔细思考的angular落之后,使用PRNG的刺激有时可以find其他的东西。
在“ 美丽的代码 ”一书中,有一章叫做“美丽的testing”,他在那里通过二进制searchalgorithm的testing策略。 一个段落被称为“随机testing行为”,其中他创build随机数组彻底testingalgorithm。 你可以在谷歌图书第95页上在线阅读这些内容,但是这本书是值得拥有的。
所以基本上这只是表明生成随机数据进行testing是一个可行的select。
如果你正在做TDD,那么我认为随机数据是一个很好的方法。 如果你的testing是用常量编写的,那么你只能保证你的代码适用于特定的值。 如果你的testing是随机失败的构build服务器可能是一个testing如何写的问题。
随机数据将有助于确保将来的重构不会依赖于魔术常数。 毕竟,如果你的testing是你的文档,那么常量的存在意味着它只需要为那些常量工作?
我夸大,但我更喜欢随机数据注入我的testing作为一个标志,“这个variables的价值不应该影响这个testing的结果”。
我会说,如果你使用一个随机variables,然后基于这个variables分叉你的testing,那么这是一种气味。
对于那些正在testing的人来说,一个好处是任意的数据显然并不重要。 我看过太多涉及数十个数据的testing,可能很难说出需要怎样的方式以及恰恰如此。 例如,如果地址validation方法使用特定的邮政编码进行testing,并且所有其他数据都是随机的,那么您可以确定邮政编码是唯一重要的部分。
- 如果它是一个随机值并且testing失败,我们需要a)修复这个对象,并且b)强迫我们每次testing这个值,所以我们知道它是有效的,但是因为它是随机的,所以我们不知道这个值是什么
如果你的testing用例没有准确地logging它正在testing的内容,也许你需要重新编码testing用例。 我总是希望有可以返回的testing用例的日志,以便我确切地知道是什么原因导致它无法使用静态或随机数据。
你的同事正在做模糊testing ,虽然他不知道。 它们在服务器系统中特别有价值。
你应该问自己什么是你的testing的目标。
unit testing是关于validation逻辑,代码stream和对象交互的。 使用随机值试图实现不同的目标,从而减lesstesting的重点和简单性。 由于可读性原因(生成UUID,ID,密钥等)是可接受的。
特别是对于unit testing,即使一旦这个方法成功find问题,我也记不起来。 但是我看到很多确定性问题(在testing中)试图用随机值来聪明地工作,主要是随机的date。
模糊testing是集成testing和端到端testing的有效方法。
你能产生一次随机数据吗(我的意思是一次,而不是每次testing一次),然后在所有的testing中使用它?
我可以肯定地看到创build随机数据的价值,以testing你没有想到的情况,但是你是对的,unit testing可以随机通过或失败是一件坏事。
我赞成随机testing,然后写下来。 但是,它们在特定的构build环境中是否合适以及它们应该包含哪些testing套件是一个更加细微的问题。
在本地运行(例如,在开箱即可过夜),随机testing发现了明显和模糊的错误。 这些晦涩难懂的东西已经足够了,我认为随机testing真的是唯一现实的testing方法。 作为一个testing,我通过随机testing发现了一个难以发现的错误,并且有六位开发人员在其中发生的function(大约十几行代码)。 没有人能够发现它。
许多针对随机数据的论点都是“testing不可重现”的口味。 然而,一个写得很好的随机testing将捕获用于启动随机种子的种子,并在失败时输出。 除了允许您手动重复testing外,您还可以轻松创build新的testing,通过对testing的种子进行硬编码来testing特定的问题。 当然,对这种情况进行明确的testing可能更好,但懒惰有其优点,甚至可以让你从一个失败的种子中自动生成新的testing用例。
然而,你所做的一点我不能辩论,就是打破了构build系统。 大多数构build和持续集成testing都希望testing每次都能做同样的事情。 所以随机失败的testing会产生混乱,随机失败,并指向无害的变化。
一个解决scheme是,仍然运行你的随机testing作为构build和CItesting的一部分,但运行一个固定的种子,固定数量的迭代 。 因此,testing总是做同样的事情,但仍然探索了一堆input空间(如果你运行它多次迭代)。
在本地,例如,当改变相关的类时,可以自由地运行它以获得更多迭代或与其他种子。 如果随机testing变得越来越stream行,你甚至可以想象一个已知是随机的,可以用不同的种子运行的特定testing套件(因此随着时间的推移,覆盖范围越来越大),而且失败并不意味着同样的事情作为确定性的CI系统(即,运行与代码更改不是1:1关联,所以当事情失败时,您不会指向特定的更改)。
随机testing有很多需要说的,尤其是写得很好的testing,所以不要太急于解雇他们!
如果您使用随机input进行testing,则需要logginginput,以便查看这些值。 这样,如果遇到一些边缘情况,您可以编写testing来重现它。 我听说过人们不使用随机input的相同原因,但是一旦您了解了用于特定testing运行的实际值,那么它就不是什么问题。
“任意”数据的概念也是非常有用的,用来表示一些不重要的东西。 我们有一些验收testing,在有很多噪声数据与手头testing无关的情况下,我们会想到这些testing。
根据您的对象/应用程序,随机数据将在负载testing中占有一席之地。 我认为更重要的是使用明确testing数据边界条件的数据。
我们今天刚碰到这个 我想要伪随机 (所以它看起来像大小压缩的audio数据)。 我想我也想要确定性的 。 rand()在OSX上不同于Linux。 除非我重播种子,否则可能随时改变。 所以我们将其改为确定性的,但仍然是随机的:testing是可重复的,与使用jar装数据一样多(但是写得更方便)。
这不是通过代码path随机蛮力testing。 这是区别:仍然是确定性的,仍然是可重复的,仍然使用看起来像实际input的数据来对复杂逻辑中的边缘情况运行一组有趣的检查。 仍然是unit testing。
这还有资格是随机的吗? 让我们来谈谈啤酒。 🙂
我可以设想testing数据问题的三个解决scheme:
- 用固定数据进行testing
- 随机数据testing
- 一次生成随机数据,然后将其用作固定数据
我会build议做所有上述 。 也就是说,写一个可重复的unit testing,用一些边缘情况下,使用你的大脑和一些随机数据,你只能生成一次。 然后写一组随机testing,你也运行。
应该永远不要期望随机testing能够捕捉到可重复testing错过的东西。 你应该用可重复的testing覆盖所有的东西,并且考虑随机testing是一个奖励。 如果他们发现了什么,那应该是你不能合理预测的; 一个真正的古怪。
如果你的家伙没有看到他是否已经修好了,你怎么能再次进行testing? 即他失去了testing的可重复性。
虽然我认为在testing中扔掉大量的随机数据可能会有一些价值,正如其他回复中所提到的,它在负载testing的标题下比其他任何东西都要低。 这几乎是一个“希望testing”的做法。 我认为,实际上,你的家伙根本就不是在想他想要testing的东西,而是通过希望随机性来弥补这种缺乏思想,最终会陷入一些神秘的错误。
所以我和他一起使用的论点是他是懒惰的。 或者换句话说,如果他没有花时间去理解他想要testing的东西,那可能表明他并不真正了解他所写的代码。