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 Equality
s 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 Double
s 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 Prettifier
s
and create extractors for Throwable
s 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-2024 Artima, Inc. All Rights Reserved.