2

私は Scala の初心者で、初めての Scalacheck スイートを作成しています。

私のプログラムには、 の各要素が の対応する要素より厳密に大きい場合に(List[Double], List[Double])のみ整形式の のように見えるデータ構造があります。_1_2

実際にはもう少し複雑なので (ただし、この MWE の目的のために、すべてが存在するふりをすることができます)、そのためのカスタム ジェネレーターを作成しました。

次に、2 つの簡単なテスト (すべての中で最も簡単なものを含む1 == 1) を追加しましたが、どちらの場合もテストは失敗し、次のメッセージが表示されます。Gave up after only XX passed tests. YYY tests were discarded.

なぜですか、どうすれば修正できますか?

私のテストスイートと出力が添付されています。


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
4

1 に答える 1

3

arbitrary[Double].suchThat(_ > low)これはあなたの問題です。 suchThat条件が false であるすべてのケースを破棄します。2 つのランダムな値を取得し、それらの値の 1 つが他の値よりも大きくなるすべてのケースを破棄します。値を破棄する代わりに、条件が満たされるまで新しい値を生成するretryUntil代わりにwhich を使用できますが、これには、条件が非常に低い場合に長い時間がかかるか、永久にループする可能性があるという欠点があります (非常に高い値を取得した場合を想像してください)。 suchThatforlowの場合、それよりも大きな高値を取得するために長時間ループするか、または可能な限り最大の double 値を低くするほど不運な場合は永久にループする可能性があります。

うまくいくのは、とGen.choose(low, Double.MaxValue)の間の値を選択することです(可能な限り最大の倍精度)。 lowDouble.MaxValue

chooseまたはなどのメソッドを使用しoneOfてジェネレーターが必要な値のみを選択するように制限することは、通常、可能な任意の値を生成して無効なケースを破棄または再試行するよりも優れています。これは、可能性の合計と比較して基準に適合しないケースが非常に少なく、有効なケースがこれらの方法を使用して簡単に定義できない場合にのみ実行する必要があります。

于 2017-07-25T13:33:55.860 に答える