Property based testing in Scala



Property based testing in Scala

0 0


PropertyBasedTestingScalaCheck

Slides and example code about property based testing

On Github TimSoethout / PropertyBasedTestingScalaCheck

Property based testing in Scala

ScalaTest with ScalaCheck

Scala Community ING

By Tim Soethout

Property based testing

  • Different way of testing
  • Declarative
  • Logic properties
  • Abstraction over values
    • Declarative way to say what the unit under testing should do
    • Think in logic formula's
    • Abstraction over values

Properties

$\forall s : String \rightarrow s.reverse.reverse \equiv s$

or:

forAll((s: String) => s.reverse.reverse == s)
+ String.should be the same after reversing twice: OK, passed 100 tests.

ScalaCheck

Checking properties on random datasets created by generators

  • Property-based testing for Scala
  • Inspired on Haskell's QuickCheck
  • Generates test data with corner cases
  • Guides programmer to writing pure functions (TTD with property based checking)
  • Can be used in interactively in REPL
  • Can be used to test Java code (or any JVM-language for that matter)
  • Works autonomously or with ScalaTest or Specs2
  • Shrinking strategies to reduce the counter example

Simple Example

def reverseStrings(list: List[String]): List[String] = {
 list match {
    case Nil => Nil
    case (x :: xs) => reverseStrings(xs) ++ List(x)
  }
}
            

ScalaCheck Autonomous

property("should be the same after reversing twice") =
  forAll((ss: List[String]) => reverseStrings(reverseStrings(ss)) == ss)
        

ScalaTest with ScalaCheck

behavior of "reverseStrings"      
it should "give the same after reversing twice" in {
  forAll {
    (ss: List[String]) => 
      reverseStrings(reverseStrings(ss)) should equal(ss)
  }
}
        

Property Test Strategies

  • Do not redo your implementation in your test
  • Test multiple (trivial) properties
  • Think backwards (generate the output: $\forall l : SortedList \rightarrow shuffle(l).sort \equiv l$)
  • Use a slower, different or proven way to find the correct answers (- maybe your previous implementation that you are improving)

Generators

Generators for primitive types and case classes are provided

Or roll your own:
def bbans: Gen[String] =
  for {
    n <- Gen.chooseNum(0, 9999999)
  } yield n.toString
          

Demo and code

Concluding

  • Property based checking with ScalaCheck
  • Extra tool in testing tool belt
  • Can test non-Scala code

THE END

BY Tim Soethout / tim.soethout@ing.nl

Slides / Code with more examples