使用嵌套的forAll在ScalaCheck中生成的对象之间共享元素

Sharing elements between generated objects in ScalaCheck using nested forAll

最近开始使用 Scala 编码,我尝试编写一些基于属性的测试用例。在这里,我试图生成模拟我正在测试的系统的原始数据。目标是首先生成基本元素(ctrlidz),然后使用这些值生成两个类(A1B1),最后检查它们的属性。我首先尝试了以下 -

import org.scalatest._

import prop._

import scala.collection.immutable._

import org.scalacheck.{Gen, Arbitrary}



caseclass A(

  controller: String,

  id: Double,

  x: Double

)



caseclass B(

  controller: String,

  id: Double,

  y: Double

)



object BaseGenerators {

  val ctrl = Gen.const("ABC")

  val idz = Arbitrary.arbitrary[Double]

}



trait Generators {

  val obj = BaseGenerators



  val A1 = for {

    controller <- obj.ctrl

    id <- obj.idz

    x <- Arbitrary.arbitrary[Double]

  } yield A(controller, id, x)



  val B1 = for {

    controller <- obj.ctrl

    id <- obj.idz

    y <- Arbitrary.arbitrary[Double]

  } yield B(controller, id, y)



}



class Something extends PropSpec with PropertyChecks with Matchers with Generators{



  property("Controllers are equal") {

    forAll(A1, B1) {

      (a:A,b:B) => 

        a.controller should be (b.controller)

    }

  }



  property("IDs are equal") {

    forAll(A1, B1) {

      (a:A,b:B) => 

        a.id should be (b.id)

    }

  }



}

[info] Something:

[info] - Controllers are equal

[info] - IDs are equal *** FAILED ***

[info]  TestFailedException was thrown during property evaluation.

[info]   Message: 1.1794559135007427E-271 was not equal to 7.871712821709093E212

[info]   Location: (testnew.scala:52)

[info]   Occurred when passed generated values (

[info]    arg0 = A(ABC,1.1794559135007427E-271,-1.6982696700585273E-23),

[info]    arg1 = B(ABC,7.871712821709093E212,-8.820696498155311E234)

[info]   )

caseclass Popo(

  controller: String,

  id: Double,

  someA: Gen[A],

  someB: Gen[B]

)



trait Generators {

  val obj = for {

    ctrl <- Gen.alphaStr

    idz <- Arbitrary.arbitrary[Double]

    val someA = for {

      x <- Arbitrary.arbitrary[Double]

    } yield A(ctrl, idz, someA)

    val someB = for {

      y <- Arbitrary.arbitrary[Double]

    } yield B(ctrl, idz, y)

  } yield Popo(ctrl, idz, x, someB)

}



class Something extends PropSpec with PropertyChecks with Matchers with Generators{



  property("Controllers are equal") {

    forAll(obj) {

      (x: Popo) => 

      forAll(x.someA, x.someB) {

        (a:A,b:B) => 

          a.controller should be (b.controller)

      }

    }

  }



  property("IDs are equal") {

    forAll(obj) {

      (x: Popo) =>

      forAll(x.someA, x.someB) {

        (a:A,b:B) => 

          a.id should be (b.id)

      }

    }

  }

}

[info] Something:

[info] - Controllers are equal

[info] - IDs are equal

[info] ScalaTest

[info] Run completed in 335 milliseconds.

[info] Total number of tests run: 2

[info] Suites: completed 1, aborted 0

[info] Tests: succeeded 2, failed 0, canceled 0, ignored 0, pending 0

[info] All tests passed.
import org.scalacheck.Gen

import org.scalacheck.Arbitrary

import org.scalacheck.Prop

import org.scalacheck.Prop.AnyOperators

import org.scalacheck.Properties



caseclass A(

 controller: String,

 id: Double,

 x: Double

)



caseclass B(

 controller: String,

 id: Double,

 y: Double

)



object BaseGenerators {

 val ctrl = Gen.const("ABC")

 val idz = Arbitrary.arbitrary[Double]

}



object Generators {

 val obj = BaseGenerators



 val genAB: Gen[(A,B)] = for {

  controller <- obj.ctrl

  id <- obj.idz

  x <- Arbitrary.arbitrary[Double]

  y <- Arbitrary.arbitrary[Double]

  val a = A(controller, id, x)

  val b = B(controller, id, y)

 } yield (a, b)                     // !

}



class Something extends Properties("Something") {



 property("Controllers and IDs are equal") = {

  Prop.forAll(Generators.genAB) { case (a: A, b: B) => // !

   a.controller ?= b.controller && a.id ?= b.id

  }

 }

}

object Generators {

 val obj = BaseGenerators



 val genA = for {

  controller <- obj.ctrl

  id <- obj.idz

  x <- Arbitrary.arbitrary[Double]

 } yield A(controller, id, x)



 def genB(a: A) = for {                 // !

  y <- Arbitrary.arbitrary[Double]

 } yield B(a.controller, a.id, y)

}



class Something extends Properties("Something") {



 implicitval arbA: Arbitrary[A] = Arbitrary {

  Generators.genA

 }



 property("Controllers and IDs are equal") = {

  Prop.forAll { a: A =>                // !

   Prop.forAll(Generators.genB(a)) { b: B =>     // !

    (a.controller ?= b.controller) && (a.id ?= b.id)

   }

  }

 }

}

在终端中运行 sbt test 给了我以下 -

import org.scalatest._

import prop._

import scala.collection.immutable._

import org.scalacheck.{Gen, Arbitrary}



caseclass A(

  controller: String,

  id: Double,

  x: Double

)



caseclass B(

  controller: String,

  id: Double,

  y: Double

)



object BaseGenerators {

  val ctrl = Gen.const("ABC")

  val idz = Arbitrary.arbitrary[Double]

}



trait Generators {

  val obj = BaseGenerators



  val A1 = for {

    controller <- obj.ctrl

    id <- obj.idz

    x <- Arbitrary.arbitrary[Double]

  } yield A(controller, id, x)



  val B1 = for {

    controller <- obj.ctrl

    id <- obj.idz

    y <- Arbitrary.arbitrary[Double]

  } yield B(controller, id, y)



}



class Something extends PropSpec with PropertyChecks with Matchers with Generators{



  property("Controllers are equal") {

    forAll(A1, B1) {

      (a:A,b:B) => 

        a.controller should be (b.controller)

    }

  }



  property("IDs are equal") {

    forAll(A1, B1) {

      (a:A,b:B) => 

        a.id should be (b.id)

    }

  }



}

[info] Something:

[info] - Controllers are equal

[info] - IDs are equal *** FAILED ***

[info]  TestFailedException was thrown during property evaluation.

[info]   Message: 1.1794559135007427E-271 was not equal to 7.871712821709093E212

[info]   Location: (testnew.scala:52)

[info]   Occurred when passed generated values (

[info]    arg0 = A(ABC,1.1794559135007427E-271,-1.6982696700585273E-23),

[info]    arg1 = B(ABC,7.871712821709093E212,-8.820696498155311E234)

[info]   )

caseclass Popo(

  controller: String,

  id: Double,

  someA: Gen[A],

  someB: Gen[B]

)



trait Generators {

  val obj = for {

    ctrl <- Gen.alphaStr

    idz <- Arbitrary.arbitrary[Double]

    val someA = for {

      x <- Arbitrary.arbitrary[Double]

    } yield A(ctrl, idz, someA)

    val someB = for {

      y <- Arbitrary.arbitrary[Double]

    } yield B(ctrl, idz, y)

  } yield Popo(ctrl, idz, x, someB)

}



class Something extends PropSpec with PropertyChecks with Matchers with Generators{



  property("Controllers are equal") {

    forAll(obj) {

      (x: Popo) => 

      forAll(x.someA, x.someB) {

        (a:A,b:B) => 

          a.controller should be (b.controller)

      }

    }

  }



  property("IDs are equal") {

    forAll(obj) {

      (x: Popo) =>

      forAll(x.someA, x.someB) {

        (a:A,b:B) => 

          a.id should be (b.id)

      }

    }

  }

}

[info] Something:

[info] - Controllers are equal

[info] - IDs are equal

[info] ScalaTest

[info] Run completed in 335 milliseconds.

[info] Total number of tests run: 2

[info] Suites: completed 1, aborted 0

[info] Tests: succeeded 2, failed 0, canceled 0, ignored 0, pending 0

[info] All tests passed.
import org.scalacheck.Gen

import org.scalacheck.Arbitrary

import org.scalacheck.Prop

import org.scalacheck.Prop.AnyOperators

import org.scalacheck.Properties



caseclass A(

 controller: String,

 id: Double,

 x: Double

)



caseclass B(

 controller: String,

 id: Double,

 y: Double

)



object BaseGenerators {

 val ctrl = Gen.const("ABC")

 val idz = Arbitrary.arbitrary[Double]

}



object Generators {

 val obj = BaseGenerators



 val genAB: Gen[(A,B)] = for {

  controller <- obj.ctrl

  id <- obj.idz

  x <- Arbitrary.arbitrary[Double]

  y <- Arbitrary.arbitrary[Double]

  val a = A(controller, id, x)

  val b = B(controller, id, y)

 } yield (a, b)                     // !

}



class Something extends Properties("Something") {



 property("Controllers and IDs are equal") = {

  Prop.forAll(Generators.genAB) { case (a: A, b: B) => // !

   a.controller ?= b.controller && a.id ?= b.id

  }

 }

}

object Generators {

 val obj = BaseGenerators



 val genA = for {

  controller <- obj.ctrl

  id <- obj.idz

  x <- Arbitrary.arbitrary[Double]

 } yield A(controller, id, x)



 def genB(a: A) = for {                 // !

  y <- Arbitrary.arbitrary[Double]

 } yield B(a.controller, a.id, y)

}



class Something extends Properties("Something") {



 implicitval arbA: Arbitrary[A] = Arbitrary {

  Generators.genA

 }



 property("Controllers and IDs are equal") = {

  Prop.forAll { a: A =>                // !

   Prop.forAll(Generators.genB(a)) { b: B =>     // !

    (a.controller ?= b.controller) && (a.id ?= b.id)

   }

  }

 }

}

现在很容易看出为什么第二个属性失败了。因为每次我产生 A1B1 我都会为 id 而不是为 ctrl 产生不同的值,因为它是一个常数。以下是我的第二种方法,其中,我创建嵌套 for-yield 来尝试实现我的目标 -

import org.scalatest._

import prop._

import scala.collection.immutable._

import org.scalacheck.{Gen, Arbitrary}



caseclass A(

  controller: String,

  id: Double,

  x: Double

)



caseclass B(

  controller: String,

  id: Double,

  y: Double

)



object BaseGenerators {

  val ctrl = Gen.const("ABC")

  val idz = Arbitrary.arbitrary[Double]

}



trait Generators {

  val obj = BaseGenerators



  val A1 = for {

    controller <- obj.ctrl

    id <- obj.idz

    x <- Arbitrary.arbitrary[Double]

  } yield A(controller, id, x)



  val B1 = for {

    controller <- obj.ctrl

    id <- obj.idz

    y <- Arbitrary.arbitrary[Double]

  } yield B(controller, id, y)



}



class Something extends PropSpec with PropertyChecks with Matchers with Generators{



  property("Controllers are equal") {

    forAll(A1, B1) {

      (a:A,b:B) => 

        a.controller should be (b.controller)

    }

  }



  property("IDs are equal") {

    forAll(A1, B1) {

      (a:A,b:B) => 

        a.id should be (b.id)

    }

  }



}

[info] Something:

[info] - Controllers are equal

[info] - IDs are equal *** FAILED ***

[info]  TestFailedException was thrown during property evaluation.

[info]   Message: 1.1794559135007427E-271 was not equal to 7.871712821709093E212

[info]   Location: (testnew.scala:52)

[info]   Occurred when passed generated values (

[info]    arg0 = A(ABC,1.1794559135007427E-271,-1.6982696700585273E-23),

[info]    arg1 = B(ABC,7.871712821709093E212,-8.820696498155311E234)

[info]   )

caseclass Popo(

  controller: String,

  id: Double,

  someA: Gen[A],

  someB: Gen[B]

)



trait Generators {

  val obj = for {

    ctrl <- Gen.alphaStr

    idz <- Arbitrary.arbitrary[Double]

    val someA = for {

      x <- Arbitrary.arbitrary[Double]

    } yield A(ctrl, idz, someA)

    val someB = for {

      y <- Arbitrary.arbitrary[Double]

    } yield B(ctrl, idz, y)

  } yield Popo(ctrl, idz, x, someB)

}



class Something extends PropSpec with PropertyChecks with Matchers with Generators{



  property("Controllers are equal") {

    forAll(obj) {

      (x: Popo) => 

      forAll(x.someA, x.someB) {

        (a:A,b:B) => 

          a.controller should be (b.controller)

      }

    }

  }



  property("IDs are equal") {

    forAll(obj) {

      (x: Popo) =>

      forAll(x.someA, x.someB) {

        (a:A,b:B) => 

          a.id should be (b.id)

      }

    }

  }

}

[info] Something:

[info] - Controllers are equal

[info] - IDs are equal

[info] ScalaTest

[info] Run completed in 335 milliseconds.

[info] Total number of tests run: 2

[info] Suites: completed 1, aborted 0

[info] Tests: succeeded 2, failed 0, canceled 0, ignored 0, pending 0

[info] All tests passed.
import org.scalacheck.Gen

import org.scalacheck.Arbitrary

import org.scalacheck.Prop

import org.scalacheck.Prop.AnyOperators

import org.scalacheck.Properties



caseclass A(

 controller: String,

 id: Double,

 x: Double

)



caseclass B(

 controller: String,

 id: Double,

 y: Double

)



object BaseGenerators {

 val ctrl = Gen.const("ABC")

 val idz = Arbitrary.arbitrary[Double]

}



object Generators {

 val obj = BaseGenerators



 val genAB: Gen[(A,B)] = for {

  controller <- obj.ctrl

  id <- obj.idz

  x <- Arbitrary.arbitrary[Double]

  y <- Arbitrary.arbitrary[Double]

  val a = A(controller, id, x)

  val b = B(controller, id, y)

 } yield (a, b)                     // !

}



class Something extends Properties("Something") {



 property("Controllers and IDs are equal") = {

  Prop.forAll(Generators.genAB) { case (a: A, b: B) => // !

   a.controller ?= b.controller && a.id ?= b.id

  }

 }

}

object Generators {

 val obj = BaseGenerators



 val genA = for {

  controller <- obj.ctrl

  id <- obj.idz

  x <- Arbitrary.arbitrary[Double]

 } yield A(controller, id, x)



 def genB(a: A) = for {                 // !

  y <- Arbitrary.arbitrary[Double]

 } yield B(a.controller, a.id, y)

}



class Something extends Properties("Something") {



 implicitval arbA: Arbitrary[A] = Arbitrary {

  Generators.genA

 }



 property("Controllers and IDs are equal") = {

  Prop.forAll { a: A =>                // !

   Prop.forAll(Generators.genB(a)) { b: B =>     // !

    (a.controller ?= b.controller) && (a.id ?= b.id)

   }

  }

 }

}

在第二种方法中运行 sbt test 告诉我所有测试都通过了。

import org.scalatest._

import prop._

import scala.collection.immutable._

import org.scalacheck.{Gen, Arbitrary}



caseclass A(

  controller: String,

  id: Double,

  x: Double

)



caseclass B(

  controller: String,

  id: Double,

  y: Double

)



object BaseGenerators {

  val ctrl = Gen.const("ABC")

  val idz = Arbitrary.arbitrary[Double]

}



trait Generators {

  val obj = BaseGenerators



  val A1 = for {

    controller <- obj.ctrl

    id <- obj.idz

    x <- Arbitrary.arbitrary[Double]

  } yield A(controller, id, x)



  val B1 = for {

    controller <- obj.ctrl

    id <- obj.idz

    y <- Arbitrary.arbitrary[Double]

  } yield B(controller, id, y)



}



class Something extends PropSpec with PropertyChecks with Matchers with Generators{



  property("Controllers are equal") {

    forAll(A1, B1) {

      (a:A,b:B) => 

        a.controller should be (b.controller)

    }

  }



  property("IDs are equal") {

    forAll(A1, B1) {

      (a:A,b:B) => 

        a.id should be (b.id)

    }

  }



}

[info] Something:

[info] - Controllers are equal

[info] - IDs are equal *** FAILED ***

[info]  TestFailedException was thrown during property evaluation.

[info]   Message: 1.1794559135007427E-271 was not equal to 7.871712821709093E212

[info]   Location: (testnew.scala:52)

[info]   Occurred when passed generated values (

[info]    arg0 = A(ABC,1.1794559135007427E-271,-1.6982696700585273E-23),

[info]    arg1 = B(ABC,7.871712821709093E212,-8.820696498155311E234)

[info]   )

caseclass Popo(

  controller: String,

  id: Double,

  someA: Gen[A],

  someB: Gen[B]

)



trait Generators {

  val obj = for {

    ctrl <- Gen.alphaStr

    idz <- Arbitrary.arbitrary[Double]

    val someA = for {

      x <- Arbitrary.arbitrary[Double]

    } yield A(ctrl, idz, someA)

    val someB = for {

      y <- Arbitrary.arbitrary[Double]

    } yield B(ctrl, idz, y)

  } yield Popo(ctrl, idz, x, someB)

}



class Something extends PropSpec with PropertyChecks with Matchers with Generators{



  property("Controllers are equal") {

    forAll(obj) {

      (x: Popo) => 

      forAll(x.someA, x.someB) {

        (a:A,b:B) => 

          a.controller should be (b.controller)

      }

    }

  }



  property("IDs are equal") {

    forAll(obj) {

      (x: Popo) =>

      forAll(x.someA, x.someB) {

        (a:A,b:B) => 

          a.id should be (b.id)

      }

    }

  }

}

[info] Something:

[info] - Controllers are equal

[info] - IDs are equal

[info] ScalaTest

[info] Run completed in 335 milliseconds.

[info] Total number of tests run: 2

[info] Suites: completed 1, aborted 0

[info] Tests: succeeded 2, failed 0, canceled 0, ignored 0, pending 0

[info] All tests passed.
import org.scalacheck.Gen

import org.scalacheck.Arbitrary

import org.scalacheck.Prop

import org.scalacheck.Prop.AnyOperators

import org.scalacheck.Properties



caseclass A(

 controller: String,

 id: Double,

 x: Double

)



caseclass B(

 controller: String,

 id: Double,

 y: Double

)



object BaseGenerators {

 val ctrl = Gen.const("ABC")

 val idz = Arbitrary.arbitrary[Double]

}



object Generators {

 val obj = BaseGenerators



 val genAB: Gen[(A,B)] = for {

  controller <- obj.ctrl

  id <- obj.idz

  x <- Arbitrary.arbitrary[Double]

  y <- Arbitrary.arbitrary[Double]

  val a = A(controller, id, x)

  val b = B(controller, id, y)

 } yield (a, b)                     // !

}



class Something extends Properties("Something") {



 property("Controllers and IDs are equal") = {

  Prop.forAll(Generators.genAB) { case (a: A, b: B) => // !

   a.controller ?= b.controller && a.id ?= b.id

  }

 }

}

object Generators {

 val obj = BaseGenerators



 val genA = for {

  controller <- obj.ctrl

  id <- obj.idz

  x <- Arbitrary.arbitrary[Double]

 } yield A(controller, id, x)



 def genB(a: A) = for {                 // !

  y <- Arbitrary.arbitrary[Double]

 } yield B(a.controller, a.id, y)

}



class Something extends Properties("Something") {



 implicitval arbA: Arbitrary[A] = Arbitrary {

  Generators.genA

 }



 property("Controllers and IDs are equal") = {

  Prop.forAll { a: A =>                // !

   Prop.forAll(Generators.genB(a)) { b: B =>     // !

    (a.controller ?= b.controller) && (a.id ?= b.id)

   }

  }

 }

}

有没有更好/替代的方法来重现我想要的结果?嵌套 forAll 对我来说似乎相当笨拙。如果我的依赖图中有 R -> S -> ... V -> W 用于共享元素的对象,那么我将不得不创建尽可能多的嵌套 forAll.


我将在 Scalacheck 中给出答案。我知道 Scalatest 很受欢迎,但我发现将其包含在有关 Scalacheck 的问题中会分散注意力,尤其是当没有理由没有理由无法编写示例时。

您似乎想测试 AB,但它们共享信息。表示该依赖关系的一种方法是您编写的 Popo 类。它既包含共享信息,也包含 AB 的生成值。另一种选择是在类中生成 AB 之间的共享值。

最简单的解决方案是成对生成 AB(两个元组)。

不幸的是,有一些技巧可以让它发挥作用。您需要在 forAll 属性中使用 case 关键字。您不能为 Arbitrary 元组的 implicit 值提供证据,因此您必须在 forAll.

中明确指定元组的生成器

import org.scalatest._

import prop._

import scala.collection.immutable._

import org.scalacheck.{Gen, Arbitrary}



caseclass A(

  controller: String,

  id: Double,

  x: Double

)



caseclass B(

  controller: String,

  id: Double,

  y: Double

)



object BaseGenerators {

  val ctrl = Gen.const("ABC")

  val idz = Arbitrary.arbitrary[Double]

}



trait Generators {

  val obj = BaseGenerators



  val A1 = for {

    controller <- obj.ctrl

    id <- obj.idz

    x <- Arbitrary.arbitrary[Double]

  } yield A(controller, id, x)



  val B1 = for {

    controller <- obj.ctrl

    id <- obj.idz

    y <- Arbitrary.arbitrary[Double]

  } yield B(controller, id, y)



}



class Something extends PropSpec with PropertyChecks with Matchers with Generators{



  property("Controllers are equal") {

    forAll(A1, B1) {

      (a:A,b:B) => 

        a.controller should be (b.controller)

    }

  }



  property("IDs are equal") {

    forAll(A1, B1) {

      (a:A,b:B) => 

        a.id should be (b.id)

    }

  }



}

[info] Something:

[info] - Controllers are equal

[info] - IDs are equal *** FAILED ***

[info]  TestFailedException was thrown during property evaluation.

[info]   Message: 1.1794559135007427E-271 was not equal to 7.871712821709093E212

[info]   Location: (testnew.scala:52)

[info]   Occurred when passed generated values (

[info]    arg0 = A(ABC,1.1794559135007427E-271,-1.6982696700585273E-23),

[info]    arg1 = B(ABC,7.871712821709093E212,-8.820696498155311E234)

[info]   )

caseclass Popo(

  controller: String,

  id: Double,

  someA: Gen[A],

  someB: Gen[B]

)



trait Generators {

  val obj = for {

    ctrl <- Gen.alphaStr

    idz <- Arbitrary.arbitrary[Double]

    val someA = for {

      x <- Arbitrary.arbitrary[Double]

    } yield A(ctrl, idz, someA)

    val someB = for {

      y <- Arbitrary.arbitrary[Double]

    } yield B(ctrl, idz, y)

  } yield Popo(ctrl, idz, x, someB)

}



class Something extends PropSpec with PropertyChecks with Matchers with Generators{



  property("Controllers are equal") {

    forAll(obj) {

      (x: Popo) => 

      forAll(x.someA, x.someB) {

        (a:A,b:B) => 

          a.controller should be (b.controller)

      }

    }

  }



  property("IDs are equal") {

    forAll(obj) {

      (x: Popo) =>

      forAll(x.someA, x.someB) {

        (a:A,b:B) => 

          a.id should be (b.id)

      }

    }

  }

}

[info] Something:

[info] - Controllers are equal

[info] - IDs are equal

[info] ScalaTest

[info] Run completed in 335 milliseconds.

[info] Total number of tests run: 2

[info] Suites: completed 1, aborted 0

[info] Tests: succeeded 2, failed 0, canceled 0, ignored 0, pending 0

[info] All tests passed.
import org.scalacheck.Gen

import org.scalacheck.Arbitrary

import org.scalacheck.Prop

import org.scalacheck.Prop.AnyOperators

import org.scalacheck.Properties



caseclass A(

 controller: String,

 id: Double,

 x: Double

)



caseclass B(

 controller: String,

 id: Double,

 y: Double

)



object BaseGenerators {

 val ctrl = Gen.const("ABC")

 val idz = Arbitrary.arbitrary[Double]

}



object Generators {

 val obj = BaseGenerators



 val genAB: Gen[(A,B)] = for {

  controller <- obj.ctrl

  id <- obj.idz

  x <- Arbitrary.arbitrary[Double]

  y <- Arbitrary.arbitrary[Double]

  val a = A(controller, id, x)

  val b = B(controller, id, y)

 } yield (a, b)                     // !

}



class Something extends Properties("Something") {



 property("Controllers and IDs are equal") = {

  Prop.forAll(Generators.genAB) { case (a: A, b: B) => // !

   a.controller ?= b.controller && a.id ?= b.id

  }

 }

}

object Generators {

 val obj = BaseGenerators



 val genA = for {

  controller <- obj.ctrl

  id <- obj.idz

  x <- Arbitrary.arbitrary[Double]

 } yield A(controller, id, x)



 def genB(a: A) = for {                 // !

  y <- Arbitrary.arbitrary[Double]

 } yield B(a.controller, a.id, y)

}



class Something extends Properties("Something") {



 implicitval arbA: Arbitrary[A] = Arbitrary {

  Generators.genA

 }



 property("Controllers and IDs are equal") = {

  Prop.forAll { a: A =>                // !

   Prop.forAll(Generators.genB(a)) { b: B =>     // !

    (a.controller ?= b.controller) && (a.id ?= b.id)

   }

  }

 }

}

关于您关于让对象共享信息的更广泛的问题,您可以通过编写带有函数参数的生成器来表示它。但是,它仍然需要嵌套的 forAll 生成器。

import org.scalatest._

import prop._

import scala.collection.immutable._

import org.scalacheck.{Gen, Arbitrary}



caseclass A(

  controller: String,

  id: Double,

  x: Double

)



caseclass B(

  controller: String,

  id: Double,

  y: Double

)



object BaseGenerators {

  val ctrl = Gen.const("ABC")

  val idz = Arbitrary.arbitrary[Double]

}



trait Generators {

  val obj = BaseGenerators



  val A1 = for {

    controller <- obj.ctrl

    id <- obj.idz

    x <- Arbitrary.arbitrary[Double]

  } yield A(controller, id, x)



  val B1 = for {

    controller <- obj.ctrl

    id <- obj.idz

    y <- Arbitrary.arbitrary[Double]

  } yield B(controller, id, y)



}



class Something extends PropSpec with PropertyChecks with Matchers with Generators{



  property("Controllers are equal") {

    forAll(A1, B1) {

      (a:A,b:B) => 

        a.controller should be (b.controller)

    }

  }



  property("IDs are equal") {

    forAll(A1, B1) {

      (a:A,b:B) => 

        a.id should be (b.id)

    }

  }



}

[info] Something:

[info] - Controllers are equal

[info] - IDs are equal *** FAILED ***

[info]  TestFailedException was thrown during property evaluation.

[info]   Message: 1.1794559135007427E-271 was not equal to 7.871712821709093E212

[info]   Location: (testnew.scala:52)

[info]   Occurred when passed generated values (

[info]    arg0 = A(ABC,1.1794559135007427E-271,-1.6982696700585273E-23),

[info]    arg1 = B(ABC,7.871712821709093E212,-8.820696498155311E234)

[info]   )

caseclass Popo(

  controller: String,

  id: Double,

  someA: Gen[A],

  someB: Gen[B]

)



trait Generators {

  val obj = for {

    ctrl <- Gen.alphaStr

    idz <- Arbitrary.arbitrary[Double]

    val someA = for {

      x <- Arbitrary.arbitrary[Double]

    } yield A(ctrl, idz, someA)

    val someB = for {

      y <- Arbitrary.arbitrary[Double]

    } yield B(ctrl, idz, y)

  } yield Popo(ctrl, idz, x, someB)

}



class Something extends PropSpec with PropertyChecks with Matchers with Generators{



  property("Controllers are equal") {

    forAll(obj) {

      (x: Popo) => 

      forAll(x.someA, x.someB) {

        (a:A,b:B) => 

          a.controller should be (b.controller)

      }

    }

  }



  property("IDs are equal") {

    forAll(obj) {

      (x: Popo) =>

      forAll(x.someA, x.someB) {

        (a:A,b:B) => 

          a.id should be (b.id)

      }

    }

  }

}

[info] Something:

[info] - Controllers are equal

[info] - IDs are equal

[info] ScalaTest

[info] Run completed in 335 milliseconds.

[info] Total number of tests run: 2

[info] Suites: completed 1, aborted 0

[info] Tests: succeeded 2, failed 0, canceled 0, ignored 0, pending 0

[info] All tests passed.
import org.scalacheck.Gen

import org.scalacheck.Arbitrary

import org.scalacheck.Prop

import org.scalacheck.Prop.AnyOperators

import org.scalacheck.Properties



caseclass A(

 controller: String,

 id: Double,

 x: Double

)



caseclass B(

 controller: String,

 id: Double,

 y: Double

)



object BaseGenerators {

 val ctrl = Gen.const("ABC")

 val idz = Arbitrary.arbitrary[Double]

}



object Generators {

 val obj = BaseGenerators



 val genAB: Gen[(A,B)] = for {

  controller <- obj.ctrl

  id <- obj.idz

  x <- Arbitrary.arbitrary[Double]

  y <- Arbitrary.arbitrary[Double]

  val a = A(controller, id, x)

  val b = B(controller, id, y)

 } yield (a, b)                     // !

}



class Something extends Properties("Something") {



 property("Controllers and IDs are equal") = {

  Prop.forAll(Generators.genAB) { case (a: A, b: B) => // !

   a.controller ?= b.controller && a.id ?= b.id

  }

 }

}

object Generators {

 val obj = BaseGenerators



 val genA = for {

  controller <- obj.ctrl

  id <- obj.idz

  x <- Arbitrary.arbitrary[Double]

 } yield A(controller, id, x)



 def genB(a: A) = for {                 // !

  y <- Arbitrary.arbitrary[Double]

 } yield B(a.controller, a.id, y)

}



class Something extends Properties("Something") {



 implicitval arbA: Arbitrary[A] = Arbitrary {

  Generators.genA

 }



 property("Controllers and IDs are equal") = {

  Prop.forAll { a: A =>                // !

   Prop.forAll(Generators.genB(a)) { b: B =>     // !

    (a.controller ?= b.controller) && (a.id ?= b.id)

   }

  }

 }

}

相关推荐

  • Spring部署设置openshift

    Springdeploymentsettingsopenshift我有一个问题让我抓狂了三天。我根据OpenShift帐户上的教程部署了spring-eap6-quickstart代码。我已配置调试选项,并且已将Eclipse工作区与OpehShift服务器同步-服务器上的一切工作正常,但在Eclipse中出现无法消除的错误。我有这个错误:cvc-complex-type.2.4.a:Invali…
    2025-04-161
  • 检查Java中正则表达式中模式的第n次出现

    CheckfornthoccurrenceofpatterninregularexpressioninJava本问题已经有最佳答案,请猛点这里访问。我想使用Java正则表达式检查输入字符串中特定模式的第n次出现。你能建议怎么做吗?这应该可以工作:MatchResultfindNthOccurance(intn,Patternp,CharSequencesrc){Matcherm=p.matcher…
    2025-04-161
  • 如何让 JTable 停留在已编辑的单元格上

    HowtohaveJTablestayingontheeditedcell如果有人编辑JTable的单元格内容并按Enter,则内容会被修改并且表格选择会移动到下一行。是否可以禁止JTable在单元格编辑后转到下一行?原因是我的程序使用ListSelectionListener在单元格选择上同步了其他一些小部件,并且我不想在编辑当前单元格后选择下一行。Enter的默认绑定是名为selectNext…
    2025-04-161
  • Weblogic 12c 部署

    Weblogic12cdeploy我正在尝试将我的应用程序从Tomcat迁移到Weblogic12.2.1.3.0。我能够毫无错误地部署应用程序,但我遇到了与持久性提供程序相关的运行时错误。这是堆栈跟踪:javax.validation.ValidationException:CalltoTraversableResolver.isReachable()threwanexceptionatorg.…
    2025-04-161
  • Resteasy Content-Type 默认值

    ResteasyContent-Typedefaults我正在使用Resteasy编写一个可以返回JSON和XML的应用程序,但可以选择默认为XML。这是我的方法:@GET@Path("/content")@Produces({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})publicStringcontentListRequestXm…
    2025-04-161
  • 代码不会停止运行,在 Java 中

    thecodedoesn'tstoprunning,inJava我正在用Java解决项目Euler中的问题10,即"Thesumoftheprimesbelow10is2+3+5+7=17.Findthesumofalltheprimesbelowtwomillion."我的代码是packageprojecteuler_1;importjava.math.BigInteger;importjava…
    2025-04-161
  • Out of memory java heap space

    Outofmemoryjavaheapspace我正在尝试将大量文件从服务器发送到多个客户端。当我尝试发送大小为700mb的文件时,它显示了"OutOfMemoryjavaheapspace"错误。我正在使用Netbeans7.1.2版本。我还在属性中尝试了VMoption。但仍然发生同样的错误。我认为阅读整个文件存在一些问题。下面的代码最多可用于300mb。请给我一些建议。提前致谢publicc…
    2025-04-161
  • Log4j 记录到共享日志文件

    Log4jLoggingtoaSharedLogFile有没有办法将log4j日志记录事件写入也被其他应用程序写入的日志文件。其他应用程序可以是非Java应用程序。有什么缺点?锁定问题?格式化?Log4j有一个SocketAppender,它将向服务发送事件,您可以自己实现或使用与Log4j捆绑的简单实现。它还支持syslogd和Windows事件日志,这对于尝试将日志输出与来自非Java应用程序…
    2025-04-161