scalatest - Does property based testing make you duplicate code? -


i'm trying replace old unit tests property based testing (pbt), concreteley scala , scalatest - scalacheck think problem more general. simplified situation , if have method want test:

 def upcasereverse(s:string) = s.touppercase.reverse 

normally, have written unit tests like:

assertequals("gnirts", upcasereverse("string")) assertequals("", upcasereverse("")) // ... corner cases think of 

so, each test, write output expect, no problem. now, pbt, it'd :

property("strings reversed , upper-cased") {  forall { (s: string) =>    assert ( upcasereverse(s) == ???) //this problem right here!  } } 

as try write test true string inputs, find self having write logic of method again in tests. in case test :

   assert ( upcasereverse(s) == s.touppercase.reverse)  

that is, had write implementation in test make sure output correct. there way out of this? misunderstanding pbt, , should testing other properties instead, :

  • "strings should have same length original"
  • "strings should contain characters of original"
  • "strings should not contain lower case characters" ...

that plausible sounds contrived , less clear. can more experience in pbt shed light here?

edit : following @eric's sources got this post, , there's example of mean (at applying categories 1 more time): test method times in (f#):

type dollar(amount:int) = member val amount  = amount  member this.add add =      dollar (amount + add) member this.times multiplier  =      dollar (amount * multiplier) static member create amount  =      dollar amount   

the author ends writing test goes like:

let ``create times should same times create`` start multiplier =  let d0 = dollar.create start let d1 = d0.times(multiplier) let d2 = dollar.create (start * multiplier)      // ones duplicates code of times! d1 = d2 

so, in order test method, code of method duplicated in test. in case trivial multiplying, think extrapolates more complex cases.

this presentation gives clues kind of properties can write code without duplicating it.

in general useful think happens when compose method want test other methods on class:

  • size
  • ++
  • reverse
  • touppercase
  • contains

for example:

  • upcasereverse(y) ++ upcasereverse(x) == upcasereverse(x ++ y)

then think break if implementation broken. property fail if:

  1. size not preserved?
  2. not characters uppercased?
  3. the string not reversed?

1. implied 3. , think property above break 3. not break 2 (if there no uppercasing @ example). can enhance it? about:

  • upcasereverse(y) ++ x.reverse.toupper == upcasereverse(x ++ y)

i think 1 ok don't believe me , run tests!

anyway hope idea:

  1. compose other methods
  2. see if there equalities seem hold (things "round-tripping" or "idempotency" or "model-checking" in presentation)
  3. check if property break when code wrong

note 1. , 2. implemented library named quickspec , 3. "mutation testing".

addendum

about edit: times operation wrapper around * there's not test. in more complex case might want check operation:

  • has unit element
  • is associative
  • is commutative
  • is distributive addition

if of these properties fails, big surprise. if encode properties generic properties binary relation t x t -> t should able reuse them in sorts of contexts (see scalaz monoid "laws").

coming uppercasereverse example write 2 separate properties:

 "uppercasereverse must uppercase string" >> forall { s: string =>     uppercasereverse(s).forall(_.isupper)  }   "uppercasereverse reverses string regardless of case" >> forall { s: string =>     uppercasereverse(s).tolowercase === s.reverse.tolowercase  } 

this doesn't duplicate code , states 2 different things can break if code wrong.

in conclusion, had same question before , felt pretty frustrated after while found more , more cases not duplicating code in properties, when starting thinking about

  • combining tested function other functions (.isupper in first property)
  • comparing tested function simpler "model" of computation ("reverse regardless of case" in second property)

Comments

Popular posts from this blog

powershell Start-Process exit code -1073741502 when used with Credential from a windows service environment -

twig - Using Twigbridge in a Laravel 5.1 Package -

c# - LINQ join Entities from HashSet's, Join vs Dictionary vs HashSet performance -