Latest Release - Scalactic 3.2.19!
The Scalactic library is focused on constructs related to quality that are useful in both production code and tests. Although ScalaTest is tightly integrated with Scalactic, you can use Scalactic with any Scala project and any test framework. The Scalactic library has no dependencies other than Scala itself.
=== and !== operators
Scalactic provides a powerful === operator (and its complement, !==) that allows you to
For example, you can compare strings for equality after being normalized by forcing them to lowercase by customizing
Equality explicitly, like this:
import org.scalactic._
import TripleEquals._
import StringNormalizations._
import Explicitly._
("Hello" === "hello") (after being lowerCased) // true
You can also define implicit Normalization strategies for types and access
them by invoking norm methods:
import NormMethods._
implicit val strNormalization = lowerCased
"WHISPER".norm // "whisper"
"WHISPER".norm === "whisper" // true
The “after being lowerCased” syntax shown previously is provided by Scalactic'
Explicitly DSL, which allows you to specify Equality
explicitly. You can also define custom Equalitys implicitly:
implicit val strEquality =
decided by defaultEquality[String] afterBeing lowerCased
"Hello" === "hello" // true
"normalized" === "NORMALIZED" // true
You can compare numeric values for equality with a Tolerance, like this:
import Tolerance._
2.00001 === 2.0 +- 0.01 // true
Or you could use TolerantNumerics define an implicit Equality[Double] that
compares Doubles with a tolerance:
import TolerantNumerics._
implicit val dblEquality = tolerantDoubleEquality(0.01)
2.00001 === 2.0 // true
A compiler error for an equality comparison that would always yield false looks like:
import TypeCheckedTripleEquals._
Some("hi") === "hi"
error: types Some[String] and String do not adhere to the type constraint
selected for the === and !== operators; the missing implicit parameter is
of type org.scalactic.Constraint[Some[String],String]
Some("hi") === "hi"
^
Or and Every
Scalactic provides an “Either with attitude” named Or, designed for
functional error handling. Or gives you
more convenient chaining of map and flatMap calls (and for expressions) than Either and, when, combined
with Every, enables you to accumulate errors. Every is an ordered
collection of one or more elements. An Or is either Good or
Bad. An Every is either
One or Many. Here's an
example of accumulating errors with Or and Every:
import org.scalactic._ import Accumulation._ case class Person(name: String, age: Int) def parseName(input: String): String Or One[ErrorMessage] = { val trimmed = input.trim if (!trimmed.isEmpty) Good(trimmed) else Bad(One(s""""${input}" is not a valid name""")) } def parseAge(input: String): Int Or One[ErrorMessage] = { try { val age = input.trim.toInt if (age >= 0) Good(age) else Bad(One(s""""${age}" is not a valid age""")) } catch { case _: NumberFormatException => Bad(One(s""""${input}" is not a valid integer""")) } } def parsePerson(inputName: String, inputAge: String): Person Or Every[ErrorMessage] = { val name = parseName(inputName) val age = parseAge(inputAge) withGood(name, age) { Person(_, _) } }
Here are some examples of parsePerson in action:
parsePerson("Bridget Jones", "29") // Result: Good(Person(Bridget Jones,29))
parsePerson("Bridget Jones", "") // Result: Bad(One("" is not a valid integer))
parsePerson("Bridget Jones", "-29") // Result: Bad(One("-29" is not a valid age))
parsePerson("", "") // Result: Bad(Many("" is not a valid name, "" is not a valid integer))
Or offers several other ways to accumulate errors besides the withGood methods shown in the example above. See the
documentation for Or for more information.
Requirements and Snapshots
Scalactic includes a Requirements trait that offers
require, requireState, and requireNonNull methods for checking pre-conditions
that give descriptive error messages extracted via a macro. Here are some examples:
val a = -1 require(a >= 0) // throws IllegalArgumentException: -1 was not greater than or equal to 0 requireState(a >= 0) // throws IllegalStateException: -1 was not greater than or equal to 0 val b: String = null requireNonNull(a, b) // throws NullPointerException: b was null
Trait Snapshots offers a
snap method that can help you make debug and log messages that include information about
the values of variables:
val a = 1 val b = '2' val c = "3" snap(a, b, c) // Result: a was 1, b was '2', c was "3"
Scalactic also includes a TimesOnInt trait that allows you to perform
side-effecting loops a specified number of times, like this:
import TimesOnInt._ 3 times println("hello ") // Output: hello hello hello
You can also define an alternate String forms for types using Prettifiers
and create extractors for Throwables via the Catcher factory.
And that's it: Scalactic is a small, very focused library. Why not give it a try? Just visit the Quick Start page.
Scalactic is brought to you by Bill Venners, with
contributions from several other folks. It is sponsored by
Artima, Inc.
ScalaTest is free, open-source software
released under the Apache
2.0 license.
Copyright © 2009-2025 Artima, Inc. All Rights Reserved.