ScalaTest User Guide

Getting started

Selecting testing styles

Defining base classes

Writing your first test

Using assertions

Tagging your tests

Running your tests

Sharing fixtures

Sharing tests

Using matchers

Testing with mock objects

Property-based testing

Asynchronous testing

Using Selenium

Using Scala-js

Other goodies

Philosophy and design

Migrating to 3.0

Other goodies

ScalaTest has many other traits and classes that can help you address specific problems. This page gives tutorials on just a few of them. For the full list, see ScalaTest's Scaladoc documentation.

Here are links to the goodies described on this page:

Using Inside

ScalaTest's Inside trait contains an inside construct, which allows you to make statements about nested object graphs using pattern matching.

For example, given the following case classes:

case class Address(street: String, city: String, state: String, zip: String)
case class Name(first: String, middle: String, last: String)
case class Record(name: Name, address: Address, age: Int)

You could write:

inside (rec) { case Record(name, address, age) =>
  inside (name) { case Name(first, middle, last) =>
    first should be ("Sally")
    middle should be ("Ann")
    last should be ("Jones")
  }
  inside (address) { case Address(street, city, state, zip) =>
    street should startWith ("25")
    city should endWith ("Angeles")
    state should equal ("CA")
    zip should be ("12345")
  }
  age should be < 99
}

If an assertion fails, the error message will include the toString of each value passed to inside clauses enclosing the failed assertion. For example, if rec in the previous expression was defined like this:

val rec = Record(
  Name("Sally", "Anna", "Jones"),
  Address("25 Main St", "Los Angeles", "CA", "12345"),
  38
)

The error message will read:

"Ann[a]" was not equal to "Ann[]", inside Name(Sally,Anna,Jones),
inside Record(Name(Sally,Anna,Jones),Address(25 Main St,Los Angeles,CA,12345),38)

Using OptionValues

ScalaTest's OptionValues trait provides an implicit conversion that adds a value method to Option, which will return the value of the option if it is defined, or throw TestFailedException if not.

This construct allows you to express in one statement that an option should be defined and that its value should meet some expectation. Here's an example:

opt.value should be > 9

Or, using an assertion instead of a matcher expression:

assert(opt.value > 9)

Were you to simply invoke get on the Option, if the option wasn't defined, it would throw a NoSuchElementException:

val opt: Option[Int] = None

opt.get should be > 9 // opt.get throws NoSuchElementException

The NoSuchElementException would cause the test to fail, but without providing a stack depth pointing to the failing line of test code. This stack depth, provided by TestFailedException (and a few other ScalaTest exceptions), makes it quicker for users to navigate to the cause of the failure. Without OptionValues, to get a stack depth exception you would need to make two statements, like this:

val opt: Option[Int] = None

opt should be ('defined) // throws TestFailedException opt.get should be > 9

The OptionValues trait allows you to state that more concisely:

val opt: Option[Int] = None

opt.value should be > 9 // opt.value throws TestFailedException

Using EitherValues

ScalaTest's EitherValues trait provides an implicit conversion that adds left.value and right.value methods to Either, which will return the selected value of the Either if defined, or throw TestFailedException if not.

This construct allows you to express in one statement that an Either should be left or right and that its value should meet some expectation. Here's are some examples:

either1.right.value should be > 9
either2.left.value should be ("Muchas problemas")

Or, using assertions instead of matcher expressions:

assert(either1.right.value > 9)
assert(either2.left.value === "Muchas problemas")

Were you to simply invoke right.get or left.get on the Either, if the Either wasn't defined as expected (e.g., it was a Left when you expected a Right), it would throw a NoSuchElementException:

val either: Either[String, Int] = Left("Muchas problemas")

either.right.get should be > 9 // either.right.get throws NoSuchElementException

The NoSuchElementException would cause the test to fail, but without providing a stack depth pointing to the failing line of test code. This stack depth, provided by TestFailedException (and a few other ScalaTest exceptions), makes it quicker for users to navigate to the cause of the failure. Without EitherValues, to get a stack depth exception you would need to make two statements, like this:

val either: Either[String, Int] = Left("Muchas problemas")

either should be ('right) // throws TestFailedException either.right.get should be > 9

The EitherValues trait allows you to state that more concisely:

val either: Either[String, Int] = Left("Muchas problemas")

either.right.value should be > 9 // either.right.value throws TestFailedException

Using PartialFunctionValues

ScalaTest's PartialFunctionValues trait provides an implicit conversion that adds a valueAt method to PartialFunction, which will return the value (result) of the function applied to the argument passed to valueAt, or throw TestFailedException if the partial function is not defined at the argument.

This construct allows you to express in one statement that a partial function should be defined for a particular input, and that its result value should meet some expectation. Here's an example:

pf.valueAt("IV") should equal (4)

Or, using an assertion instead of a matcher expression:

assert(pf.valueAt("IV") === 4)

Were you to simply invoke apply on the PartialFunction, passing in an input value, if the partial function wasn't defined at that input, it would throw some exception, but likely not one that provides a stack depth:

// Note: a Map[K, V] is a PartialFunction[K, V]
val pf: PartialFunction[String, Int] = Map("I" -> 1, "II" -> 2, "III" -> 3, "IV" -> 4)

pf("V") should equal (5) // pf("V") throws NoSuchElementException

The NoSuchElementException thrown in this situation would cause the test to fail, but without providing a stack depth pointing to the failing line of test code. This stack depth, provided by TestFailedException (and a few other ScalaTest exceptions), makes it quicker for users to navigate to the cause of the failure. Without PartialFunctionValues, to get a stack depth exception you would need to make two statements, like this:

val pf: PartialFunction[String, Int] = Map("I" -> 1, "II" -> 2, "III" -> 3, "IV" -> 4)

pf.isDefinedAt("V") should be (true) // throws TestFailedException pf("V") should equal (5)

The PartialFunctionValues trait allows you to state that more concisely:

val pf: PartialFunction[String, Int] = Map("I" -> 1, "II" -> 2, "III" -> 3, "IV" -> 4)

pf.valueAt("V") should equal (5) // pf.valueAt("V") throws TestFailedException

Using PrivateMethodTester

ScalaTest's PrivateMethodTester trait facilitates the testing of private methods.

To test a private method, mix in trait PrivateMethodTester and create a PrivateMethod object, like this:

val decorateToStringValue = PrivateMethod[String]('decorateToStringValue)

The type parameter on PrivateMethod, in this case String, is the result type of the private method you wish to invoke. The symbol passed to the PrivateMethod.apply factory method, in this case 'decorateToStringValue, is the name of the private method to invoke. To test the private method, use the invokePrivate operator, like this:

targetObject invokePrivate decorateToStringValue(1)

Here, targetObject is a variable or singleton object name referring to the object whose private method you want to test. You pass the arguments to the private method in the parentheses after the PrivateMethod object. The result type of an invokePrivate operation will be the type parameter of the PrivateMethod object, thus you need not cast the result to use it. In other words, after creating a PrivateMethod object, the syntax to invoke the private method looks like a regular method invocation, but with the dot (.) replaced by invokePrivate. The private method is invoked dynamically via reflection, so if you have a typo in the method name symbol, specify the wrong result type, or pass invalid parameters, the invokePrivate operation will compile, but throw an exception at runtime.

One limitation to be aware of is that you can't use PrivateMethodTester to test a private method declared in a trait, because the class the trait gets mixed into will not declare that private method. Only the class generated to hold method implementations for the trait will have that private method. If you want to test a private method declared in a trait, and that method does not use any state of that trait, you can move the private method to a companion object for the trait and test it using PrivateMethodTester that way. If the private trait method you want to test uses the trait's state, your best options are to test it indirectly via a non-private trait method that calls the private method, or make the private method package access and test it directly via regular static method invocations.

Using WrapWith

You can use ScalaTest's WrapWith annotation to associate a wrapper suite with a non-Suite class, so it can be run via ScalaTest. The WrapWith annotation is similar in spirit to JUnit's RunWith annotation.

A class will be considered annotated with WrapWith if it is annotated directly or one of its superclasses (but not supertraits) are annotated with WrapWith. The wrapper suite must have a public, one-arg constructor that takes a Class instance whose type parameter is compatible with the class to wrap: i.e., the class being annotated with WrapWith. ScalaTest will load the class to wrap and construct a new instance of the wrapper suite, passing in the Class instance for the class to wrap. Here's an example:

@WrapWith(classOf[Specs1Runner])
class LegacySpec extends Specification {
  // ...
}

The Specs1Runner would need to have a public, no-arg constructor that accepts subclasses of Specification:

class Specs1Runner(clazz: Class[_ <: Specification]) {
  // ...
}

Next, learn about ScalaTest's philosophy and design.

ScalaTest is brought to you by Bill Venners and Artima.
ScalaTest is free, open-source software released under the Apache 2.0 license.

If your company loves ScalaTest, please consider sponsoring the project.

Copyright © 2009-2017 Artima, Inc. All Rights Reserved.

artima