Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Scala by the Lagoon - Random Data Generation con ScalaCheck

Scala by the Lagoon - Random Data Generation con ScalaCheck

Durante il talk verranno illustrate delle tecniche per sfruttare le caratteristiche di ScalaCheck per generare istanze random di tipi e ci sarà occasione di capire come queste istanze possano essere combinate per generare random case classes. Analizzeremo insieme le proprietà dei generatori di ScalaCheck attraverso degli esempi live di manipolazione di generatori esistenti per soddisfare le esigenze specifiche dei nostri casi di test.

Daniela Sfregola

December 21, 2016
Tweet

More Decks by Daniela Sfregola

Other Decks in Programming

Transcript

  1. HELLOOOOO > Scala Nerd > Based in London, UK >

    Scala-Italy slack channel lover! ❤
  2. SCALACHECK - PROPERTY BASED TESTING property("startsWith") = forAll { (a:

    String, b: String) => (a+b).startsWith(a) } // + String.startsWith: OK, passed 100 tests. property("concatenate") = forAll { (a: String, b: String) => (a+b).length > a.length && (a+b).length > b.length } // ! String.concat: Falsified after 0 passed tests. // > ARG_0: "" // > ARG_1: ""
  3. PROPERTY BASED TESTING - PROS > Test data is less

    biased > On failing, counter-example provided > Higher confidence that our code probably works
  4. PROPERTY BASED TESTING - CONS > Restructuring your tests as

    properties is not always immediate > Not always applicable with side effects > Configurations do affect the test result
  5. RANDOM DATA GENERATOR case class Example(text: String, n: Int) val

    example: Example = random[Example] // Example(ਈῒ!䑪⡨ᵅ䎎, 73967257)
  6. RANDOM DATA GENERATOR case class User(name: String, surname: String) "create

    a user" { val user = random[User] Post("/users", creation) ~> check { status === StatusCodes.Created assertCreation(user) } }
  7. FIX YOUR SEED Each session has a seed number associated

    Generating random data with seed -2481216758852790303 Use it to debug problematic tests export RANDOM_DATA_GENERATOR_SEED=-2481216758852790303 unset RANDOM_DATA_GENERATOR_SEED
  8. LESS BIASED TEST DATA For every session different test data

    will be randomly* selected * We can still fix the seed when needed!
  9. EASIER TO MAINTAIN case class User(name: String, surname: String, age:

    Int) "create a user" { val user = random[User] Post("/users", user) ~> check { status === Created assertCreated(user) } }
  10. IMPROVED READABILITY case class User(name: String, surname: String, age: Int)

    "reject user creation of an underage user" { val user = random[User].copy(age = 17) Post("/users", user) ~> check { status === BadRequest assertNotCreated(user) } }
  11. SCALACHECK-SHAPELESS2 AUTOMATICALLY INFERS ARBITRARY[T] IF: > T is a case

    class > T is an sealed trait ...BUT IT WILL IMPACT THE COMPILATION TIME 2 github.com/alexarchambault/scalacheck-shapeless
  12. ARBITRARY OF CUSTOM TYPE import java.util.Currency import scala.collection.JavaConversions._ implicit val

    arbitraryCurrency: Arbitrary[Currency] = Arbitrary { Gen.oneOf(Currency.getAvailableCurrencies.toSeq) } random[Currency] // java.util.Currency = OMR
  13. CUSTOMISE YOUR ARBITRARY Before: random[String] // !!ⳘԺ Ꙑ After: /**

    Generates a string of alpha characters */ implicit val arbitraryString: Arbitrary[String] = Arbitrary(Gen.alphaStr) random[String] // hqtbonxacrmvmuMpofwtasrojjnycwuoTfkrhOpli
  14. CUSTOMISE YOUR ARBITRARY case class Person(name: String, age: Int) implicit

    val arbitraryPerson: Arbitrary[Person] = Arbitrary { for { name <- Gen.oneOf("Daniela", "John", "Martin") age <- Gen.choose(0, 100) } yield Person(name, age) } random[Person] // Person(John,16)
  15. WRAP UP > A compromise between using ScalaCheck and predefined

    fixtures > Customise the data generation to your context > Do not ignore random test failures > Use it only for test purposes