Совсем недавно начал писать код в Scala, и я попытался написать несколько тестовых примеров, основанных на свойствах. Здесь я пытаюсь сгенерировать необработанные данные, которые имитируют систему, которую я тестирую. Цель состоит в том, чтобы сначала сгенерировать базовые элементы (ctrl
и idz
), затем использовать эти значения для генерации двух классов (A1
и B1
) и, наконец, проверить их свойства. Сначала я попробовал следующее -
import org.scalatest._
import prop._
import scala.collection.immutable._
import org.scalacheck.{Gen, Arbitrary}
case class A(
controller: String,
id: Double,
x: Double
)
case class 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)
}
}
}
Запуск sbt test
в терминале дал мне следующее -
[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] )
Теперь легко понять, почему второе свойство не удалось. Потому что каждый раз, когда я даю A1
и B1
, я получаю другое значение для id
, а не для ctrl
, потому что это константа. Вот мой второй подход, в котором я создаю вложенный for-yield
, чтобы попытаться достичь своей цели -
case class 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)
}
}
}
}
Запуск sbt test
при втором подходе говорит мне, что все тесты пройдены.
[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.
Есть ли лучший / альтернативный способ воспроизвести мои желаемые результаты? Вложение forAll
кажется мне довольно неуклюжим. Если бы в моем графе зависимостей для объектов, совместно использующих элементы, было R -> S -> ... V -> W
, мне пришлось бы создать столько же вложенных forAll
.