June 24, 2010

org.scalacheck a.k.a QuickCheck

Code from Rational spec use something which belong to different testing style:

package funobject
 it("should have a total order") { 
      import RationalOrderingCheck._

      check(propertyReflexive)  should be ('passed)
      check(propertySymmetry)   should be ('passed)
      check(propertyTransitive) should be ('passed)
    }

It is QuickCheck fixture.

"ScalaCheck is a powerful tool for automatic unit testing",
normal unit testing considered `manual and unreliable.

package funobject

import org.scalatest.FunSuite
import org.scalatest.matchers.ShouldMatchers
import org.scalatest.tools._

import org.scalacheck._
import org.scalacheck.Prop._
import org.scalacheck.Arbitrary.arbitrary


object ArbitraryRational { 

  import funobject._

  implicit def arbRational: Arbitrary[Rational]  = Arbitrary { 

    val genRational = for { 
      n <- Gen.choose(-5, 5)
      d <- Gen.choose(-6, 6) suchThat (_ != 0)
    } yield Rational(n, d)
    
    genRational
  }

}

object RationalOrderingCheck {  

  import ArbitraryRational._

  /** reflexive: compare(x, x) == 0, for any x of type T.
   */ 
  val propertyReflexive = forAll { 
    r: Rational =>  (r.compare(r) == 0)
  }  

  /** symmetry: compare(x, y) == z and compare(y, x) == w
   * then math.signum(z) == -math.signum(w),
   * for any x and y of type T and z and w of type Int.
   */ 
  val propertySymmetry = forAll { 
    (x: Rational, y:Rational) =>  { 
      val z = x.compare(y)
      val w = y.compare(x)
      math.signum(z) == -math.signum(w)
    }  
  }

  /** transitive: if compare(x, y) == z and compare(y, w) == v
   * and math.signum(z) >= 0 and math.signum(v) >= 0
   * then compare(x, w) == u and math.signum(z + v) == math.signum(u),
   * for any x, y, and w of type T and z, v, and u of type Int.
   */ 
  val propertyTransitive = forAll { 
    (x: Rational, y:Rational, w: Rational) =>  { 
      val z = x.compare(y)
      val v = y.compare(x)
      val u = x.compare(w)

      if (math.signum(z) > 0 &&
          math.signum(v) > 0) 
        math.signum(u) > 0
      else if (math.signum(z) < 0 &&
          math.signum(v) < 0) 
        math.signum(u) < 0
      else true
    }  
  }

}  




No comments:

Post a Comment