我是 Scala 新手,正在编写我的第一个 Scalacheck 套件。
我的程序中有一个数据结构,本质上类似于 (List[Double], List[Double])
,只有当 _1 的每个元素都存在时,该数据结构才是格式正确的
code> 严格大于 _2
的相应元素。
由于它在实践中稍微复杂一些(尽管出于本 MWE 的目的,我们可以假装它已经包含了所有内容),所以我为其编写了一个自定义生成器。
然后我添加了两个简单的测试(包括最简单的一个,1 == 1
),在这两种情况下测试都失败,并显示消息Gave up after only XX Passed Tests 。 YYY 测试被丢弃。
为什么会这样,如何解决?
附件是我的测试套件和输出。
package com.foo.bar
import org.scalacheck._
import Prop._
import Arbitrary._
object FooSpecification extends Properties("FooIntervals") {
type FooIntervals = (List[Double], List[Double])
/* This is supposed to be a tuple of lists s.t. each element of _1
* is < the corresponding element of _2
*
* e.g. (List(1,3,5), List(2,4,6))
*/
implicit def arbInterval : Arbitrary[FooIntervals] =
Arbitrary {
/**
* Yields a pair (low, high) s.t. low < high
*/
def GenPair : Gen[(Double, Double)] = for {
low <- arbitrary[Double]
high <- arbitrary[Double].suchThat(_ > low)
} yield (low, high)
/**
* Yields (List(x_1,...,x_n), List(y_1,...,y_n))
* where x_i < y_i forall i and 1 <= n < 20
*/
for {
n <- Gen.choose(1,20)
pairs : List[(Double, Double)] <- Gen.containerOfN[List, (Double, Double)](n, GenPair)
} yield ((pairs.unzip._1, pairs.unzip._2))
}
property("1 == 1") = forAll {
(b1: FooIntervals)
=>
1 == 1
}
property("_1.head < _2.head") = forAll {
(b1: FooIntervals)
=>
b1._1.head < b1._2.head
}
}
[info] ! FooIntervals.1 == 1: Gave up after only 32 passed tests. 501 tests were discarded.
[info] ! FooIntervals._1.head < _2.head: Gave up after only 28 passed tests. 501 tests were discarded.
[info] ScalaTest
[info] Run completed in 1 second, 519 milliseconds.
[info] Total number of tests run: 0
[info] Suites: completed 0, aborted 0
[info] Tests: succeeded 0, failed 0, canceled 0, ignored 0, pending 0
[info] No tests were executed.
[error] Failed: Total 1, Failed 1, Errors 0, Passed 0
[error] Failed tests:
[error] com.foo.bar.FooSpecification
最佳答案
任意[Double].suchThat(_ > low)
这是你的问题。 suchThat
将丢弃所有条件为 false 的情况。您将采用两个随机值并丢弃其中一个值大于另一个值的所有情况(这将是很多)。您可以使用 retryUntil
而不是 suchThat
,它将生成新值,直到满足条件,而不是丢弃值,但这有可能需要很长时间甚至循环的缺点如果条件不太可能出现,则永远(想象一下,如果 low
的值非常高,您可能会循环很长时间以获得大于它的高值,或者如果您足够不幸,则永远循环使最大可能的 double 值尽可能低。
有效的是 Gen.choose(low, Double.MaxValue)
它将选择 low
和 Double.MaxValue
之间的值(最大可能的双倍)。
使用 choose
或 oneOf
等方法来限制生成器仅选择您想要的值通常比生成任何可能的任意值并丢弃或重试无效情况要好。仅当与总可能性相比,只有极少数情况不符合您的标准,并且使用这些方法不易定义有效情况时,才应执行此操作。
关于scala - 为什么我使用自定义生成器进行的 Scalacheck 测试在丢弃许多案例后失败了,如何解决这个问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45304489/