Testing Scala methods

Here, we will see some simple techniques for testing Scala methods. For Scala users, this is the most familiar unit testing framework (you can also use it for testing Java code and soon for JavaScript). ScalaTest supports a number of different testing styles, each designed to support a specific type of testing need. For details, see ScalaTest User Guide at http://www.scalatest.org/user_guide/selecting_a_style. Although ScalaTest supports many styles, one of the quickest ways to get started is to use the following ScalaTest traits and write the tests in the TDD (test-driven development) style:

  1. FunSuite
  2. Assertions
  3. BeforeAndAfter

Feel free to browse the preceding URLs to learn more about these traits; that will make rest of this tutorial go smoothly.

It is to be noted that the TDD is a programming technique to develop software, and it states that you should start development from tests. Hence, it doesn't affect how tests are written, but when tests are written. There is no trait or testing style to enforce or encourage TDD in ScalaTest.FunSuite, Assertions, and BeforeAndAfter are only more similar to the xUnit testing frameworks.

There are three assertions available in the ScalaTest in any style trait:

  • assert: This is used for general assertions in your Scala program.
  • assertResult: This helps differentiate expected value from the actual values.
  • assertThrows: This is used to ensure a bit of code throws an expected exception.

The ScalaTest's assertions are defined in the trait Assertions, which is further extended by Suite. In brief, the Suite trait is the super trait for all the style traits. According to the ScalaTest documentation at http://www.scalatest.org/user_guide/using_assertions, the Assertions trait also provides the following features:

  • assume to conditionally cancel a test
  • fail to fail a test unconditionally
  • cancel to cancel a test unconditionally
  • succeed to make a test succeed unconditionally
  • intercept to ensure a bit of code throws an expected exception and then make assertions about the exception
  • assertDoesNotCompile to ensure a bit of code does not compile
  • assertCompiles to ensure a bit of code does compile
  • assertTypeError to ensure a bit of code does not compile because of a type (not parse) error
  • withClue to add more information about a failure

From the preceding list, we will show a few of them. In your Scala program, you can write assertions by calling assert and passing a Boolean expression in. You can simply start writing your simple unit test case using Assertions. The Predef is an object, where this behavior of assert is defined. Note that all the members of the Predef get imported into your every Scala source file. The following source code will print Assertion success for the following case:

package com.chapter16.SparkTesting
object SimpleScalaTest {
def main(args: Array[String]):Unit= {
val a = 5
val b = 5
assert(a == b)
println("Assertion success")
}
}

However, if you make a = 2 and b = 1, for example, the assertion will fail and you will experience the following output:

Figure 2: An example of assertion fail

If you pass a true expression, assert will return normally. However, assert will terminate abruptly with an Assertion Error if the supplied expression is false. Unlike the AssertionError and TestFailedException forms, the ScalaTest's assert provides more information that will tell you exactly in which line the test case failed or for which expression. Therefore, ScalaTest's assert provides better error messages than Scala's assert.

For example, for the following source code, you should experience TestFailedException that will tell that 5 did not equal 4:

package com.chapter16.SparkTesting
import org.scalatest.Assertions._
object SimpleScalaTest {
def main(args: Array[String]):Unit= {
val a = 5
val b = 4
assert(a == b)
println("Assertion success")
}
}

The following figure shows the output of the preceding Scala test:

Figure 3: An example of TestFailedException

The following source code explains the use of the assertResult unit test to test the result of your method:

package com.chapter16.SparkTesting
import org.scalatest.Assertions._
object AssertResult {
def main(args: Array[String]):Unit= {
val x = 10
val y = 6
assertResult(3) {
x - y
}
}
}

The preceding assertion will be failed and Scala will throw an exception TestFailedException and prints Expected 3 but got 4 (Figure 4):

Figure 4: Another example of TestFailedException

Now, let's see a unit testing to show expected exception:

package com.chapter16.SparkTesting
import org.scalatest.Assertions._
object ExpectedException {
def main(args: Array[String]):Unit= {
val s = "Hello world!"
try {
s.charAt(0)
fail()
} catch {
case _: IndexOutOfBoundsException => // Expected, so continue
}
}
}

If you try to access an array element outside the index, the preceding code will tell you if you're allowed to access the first character of the preceding string Hello world!. If your Scala program can access the value in an index, the assertion will fail. This also means that the test case has failed. Thus, the preceding test case will fail naturally since the first index contains the character H, and you should experience the following error message (Figure 5):

Figure 5: Third example of TestFailedException

However, now let's try to access the index at position -1 as follows:

package com.chapter16.SparkTesting
import org.scalatest.Assertions._
object ExpectedException {
def main(args: Array[String]):Unit= {
val s = "Hello world!"
try {
s.charAt(-1)
fail()
} catch {
case _: IndexOutOfBoundsException => // Expected, so continue
}
}
}

Now the assertion should be true, and consequently, the test case will be passed. Finally, the code will terminate normally. Now, let's check our code snippets if it will compile or not. Very often, you may wish to ensure that a certain ordering of the code that represents emerging "user error" does not compile at all. The objective is to check the strength of the library against the error to disallow unwanted result and behavior. ScalaTest's Assertions trait includes the following syntax for that purpose:

assertDoesNotCompile("val a: String = 1")

If you want to ensure that a snippet of code does not compile because of a type error (as opposed to a syntax error), use the following:

assertTypeError("val a: String = 1")

A syntax error will still result on a thrown TestFailedException. Finally, if you want to state that a snippet of code does compile, you can make that more obvious with the following:

assertCompiles("val a: Int = 1")

A complete example is shown as follows:

package com.chapter16.SparkTesting
import org.scalatest.Assertions._
object CompileOrNot {
def main(args: Array[String]):Unit= {
assertDoesNotCompile("val a: String = 1")
println("assertDoesNotCompile True")

assertTypeError("val a: String = 1")
println("assertTypeError True")

assertCompiles("val a: Int = 1")
println("assertCompiles True")

assertDoesNotCompile("val a: Int = 1")
println("assertDoesNotCompile True")
}
}

The output of the preceding code is shown in the following figure:

Figure 6: Multiple tests together

Now we would like to finish the Scala-based unit testing due to page limitation. However, for other unit test cases, you can refer the Scala test guideline at http://www.scalatest.org/user_guide.

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

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