Using ScalaCheck for property-based testing

In this section, we will cover the following topics:

  • Property-based testing
  • Creating a property-based test

Let's look at a simple property-based test. We need to import a dependency before we define properties. We also need a dependency for the ScalaCheck library, which is a library for property-based tests.

In the previous section, every test extended FunSuite. We used functional tests, but we had to provide arguments explicitly. In this example, we're extending Properties from the ScalaCheck library and testing a StringType, as follows:

object PropertyBasedTesting extends Properties("StringType")

Our ScalaCheck will generate a random string for us. If we create a property-based test for a custom type, then that is not known to the ScalaCheck. We need to provide a generator that will generate instances of that specific type.

First, let's define the first property of our string type in the following way:

property("length of strings") = forAll { (a: String, b: String) =>
a.length + b.length >= a.length
}

forAll is a method from the ScalaCheck property. We will pass an arbitrary number of arguments here, but they need to be of the type that we are testing.

Let's assume that we want to get two random strings, and in those strings, the invariants should be perceived.

If we are adding the length of string a to the length of string b, the sum of that should be greater or equal to a.length, because if b is 0 then it will be equal, as shown in the following example:

a.length + b.length >= a.length

However, this is an invariant of string and for every input string, it should be true.

The second property that we are defining is a bit more complex, as shown in the following code:

property("creating list of strings") = forAll { (a: String, b: String, c: String) =>
List(a,b,c).map(_.length).sum == a.length + b.length + c.length
}

In the preceding code, we asked the ScalaCheck runtime engine to share three strings this time, that is, a, b, and c. We will test this when we create a list of strings.

Here, we are creating a list of strings, that is, a, b, c, as shown in the following code:

List(a,b,c)

When we map every element to length, the sum of those elements should be equal to adding everything by length. Here, we have a.length + b.length + c.length and we will test the collections API to check if the map and other functions work as expected.

Let's start this property-based test to check if our properties are correct, as shown in the following example:

We can see that the StringType.length property of string passed and executed 100 tests. It could be surprising that 100 tests were executed, but let's try to see what was passed as the arguments by using the following code:

println(s"a: $a, b: $b")

We will print the a argument and b argument, and retry our property by testing the following output:

We can see that a lot of weird strings were generated, so this is an edge case that we were not able to create up-front. Property-based testing will create a very weird unique code that isn't a proper string. So, this is a great tool for testing whether our logic is working as expected for a specific type.

In the next section, we'll be testing in different versions of Spark.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.212.124