Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

Property-based testing with ScalaCheck.

1. Introduction

In 1999, Koen Claessen and John Hughes considered it necessary to find a way to test their applications automatically, just by specifying the functionalities that defined their applications.

This is how they began to develop their library of combiners through which they could generate test cases automatically for their sets of tests. The library was called QuickCheck .

This tool has been re-implemented multiple times over time. Examples of these reimplementations can be QuickTheories for Java, Theft for C or SwiftCheck for Swift.

2. Environment

The tutorial is written using the following environment:

  • Hardware: Portable MacBook Pro Retina 15 ‘(2.5 Ghz Intel Core i7, 16GB DDR3).
  • Operating System: Mac OS The High Sierra 10.13.2
  • Development environment: IntelliJ IDEA 2017.3.3

3. Why use property-based testing instead of example-based testing?

Most of the tests that are currently written are tests guided by examples, tests in which
a series of specific data are established for our functions and then it is verified that
the result of the computation corresponds to the expected values.

The focus of property-based testing or property-guided testing is based on establishing a set
of input values ​​and determining if the results obtained are correct, through properties,
understood as a statement that is always true for particular conditions .

By establishing these properties or axioms on our code, we force the realization of the exercise of delimiting the arguments, the logic and the result of each one of our functions, thus increasing the reliability of our code.

4. The bases

The ScalaCheck test unit is the properties. A property is an instance of the Prop class, which can be instantiated in multiple ways.

An example of these instantiation paths can be the forAll method, which takes a function as a parameter and creates a property. The function must return a Boolean value or another property as a result, and it can take parameters of any type, as long as there are implicit instances of the Arbitrary class for those types.

The Arbitrary instances are responsible for generating the values ​​that will receive the properties as parameters. By default, ScalaCheck will provide Arbitrary instances for the most common types (Int, string, List, etc …) but when you start working with your own objects / types it will be necessary to declare the Arbitrary instances for them.

Examples of use of forAll:

val propertyIdentityValue = Prop.forAll {

(s1: String) => (s + “”) == s

}

val propertyCompositionLength = Prop.forAll {
(s1: String, s2:String) => (s1+s2).length == s1.length + s2.length
}

As can be seen in the previous examples, the properties that must be fulfilled for the String type, namely identity and composition value, are defined.

When the check method is executed on a property, ScalaCheck will randomly generate the values ​​for the declared parameters and evaluate them on the function that gives body to the property, informing in those cases in which it finds discrepancies.

In none of the examples do we need to explicitly provide a data generator to ScalaCheck because the library itself is responsible for providing them through the mechanism of implicit.

In those cases in which it is necessary to establish a specific context, it will be possible to declare specific Generators. To define your own generator you will have to use the Gen class.

Although later on we will deepen the coding of generators, use the following code snippet as an example:

org.scalacheck.Gen.choose(0,100)

The above code will instantiate a random generator of integer values ​​between 0 and 100.

Another way to create properties is by combining existing properties.

Given two properties (propertyA and propertyB), there are the following ways to combine them:

  • propertyA && propertyB or all (propertyA, propertyB)
  • propertyA || propertyB or atLeastOne (propertyA, propertyB)
  • propertyA == propertyB

When you have a set of properties related to each other, these can be grouped through the Properties interface. This interface has a main method that can be used for a simple execution of the test based on properties.

oneOf : Choose a random value from a specific set of values.

frequency : A specific frequency of appearance can be established on each value for the established data.

If you need to create custom data generators to respond
to more complex situations, you can do it by adding different
pre-existing generators . For example:
val personaGen: Gen[(Persona, String, String, Double)] =
for {
nombre email edad } yield(Persona(nombre,email,edad))

The definition of custom generators through for-comprehension is a widespread practice, however it is not mandatory to do it in this way, the only requirement is that the function returns the appropriate type.

Arbitrary Generators

The arbitrary generators are a special type of generators that are built on existing generators (Gen instances) and that allow to simplify the properties by implementing the generation of data through the definition of implicit functions and establishing these functions in the appropriate scope.

The 2 steps necessary to create an arbitrary generator are:

  • 1.- Create a generator (for example personaGen).
  • 2.- Cover the generator with the Arbitrary class and define it as an
    implicit value.

6. Example

Take, for example, a hypothetical case of an application that manages recipes.

7. Conclusions

This change of perspective on the tests can be complex initially, since the tests based on properties demand to have the capacity to deduce the properties that our code must fulfill for all the input data sets.

This complexity brings great benefits on our code, the code that complies with these rules will be much more robust and reliable according to the established properties.

In this case, the recommendation is to have a good suite of unit tests that cover, in most cases, our code, and rely on property-based testing for that logic that has a really important weight in applications.

Throughout the tutorial the generators have also been shown, a basic tool in the very powerful property-based testing whose scope of application does not have to be reduced only to the tests based on properties.

A clear example of exploitation of the generators can be seen in the unit tests, helping in the creation of Object Mothers whose application has been an extended practice for a long time, due to the numerous advantages offered by having centralized the creation of subjects necessary for testing .

The post Property-based testing with ScalaCheck. appeared first on Target Veb.



This post first appeared on Targetveb, please read the originial post: here

Share the post

Property-based testing with ScalaCheck.

×

Subscribe to Targetveb

Get updates delivered right to your inbox!

Thank you for your subscription

×