I'm working with a piece of code that has a broad/deep case class hierarchy. For unit testing, I'd like to have "random data" populated in the classes with the ability to change the data for the fields I care about?
Example:
case class Foo(bar: Bar, name: String, value: Int)
case class Bar(baz: Baz, price: Double)
case class Baz(thing: String)
So something like:
val randomFoo = GenerateRandomData(Foo)
randomFoo.bar.baz = Baz("custom for testing")
I've heard of ScalaCheck
and Shapeless
and Scalacheck-shapeless
and they do provide some sort of random data generation but nothing with customization it seems.
I'm currently using ScalaMock
but that builds out null
fields and breaks testability for "other" tests. I used something similar in .Net like Auto Fixture and was wondering if there was something similar in Scala.
I think, you are looking for scalaz lense.
It'll do what you want.
However, I gotta say, that using random data for unit testing seems like a horrible idea. How are you going to debug a failure that happens every now and again?
You should invest some time into setting up a deterministic set of constant test objects, that also resemble the actual production data, and then just use that in your tests.
Scalacheck
does offer a const generator, that allow to define customized / constant strings:
import org.scalacheck._
val fooGen: Gen[Foo] =
for {
baz <- Gen.const("custom for testing").map(Baz)
price <- Gen.choose[Double](0, 5000)
name <- Gen.alphaStr
value <- Gen.choose(0, 100)
} yield {
val bar = Bar(baz, price)
Foo(bar, name, value)
}
Here is what we get when we run it:
scala> fooGen.sample
res6: Option[Foo] = Some(
Foo(
Bar(Baz("custom for testing"), 1854.3159675078969),
"EegNcrrQyzuazqrkturrvsqylaauxausrkwtefowpbkptiuoHtdfJjoUImgddhsnjuzpoiVpjAtjzulkMonIrzmfxonBmtZS",
64
)
)
Update : As @Dima pointed out, a way to derive random values for all fields is to use [scalacheck-shapeless]
(https://github.com/alexarchambault/scalacheck-shapeless) and lenses
for the customization, here is an example that uses Monocle
:
import org.scalacheck.{Arbitrary, Gen}
import monocle.Lens
import org.scalacheck.ScalacheckShapeless._
implicitly[Arbitrary[Foo]]
val lensBar = Lens[Foo, Bar](_.bar)(bar => _.copy(bar = bar))
val lensBaz = Lens[Bar, Baz](_.baz)(baz => _.copy(baz = baz))
val lensThing = Lens[Baz, String](_.thing)(thing => _.copy(thing = thing))
val lens = (lensBar composeLens lensBaz composeLens lensThing).set("custom for testing")
val fooGen: Gen[Foo] = Arbitrary.arbitrary[Foo].map(lens)
println(fooGen.sample)
// Display
// Some(Foo(Bar(Baz(custom for testing),1.2227226413326224E-91),〗❌䟤䉲㙯癏<,-2147483648))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With