ScalaTest/Scalactic 3.0.0 Release Notes

Version 3.0.0 is a major upgrade to ScalaTest and Scalactic, the culmination of over a year of effort. Although it includes many enhancements, we kept a close eye on compatibility with existing ScalaTest/Scalactic 2.x code. We also tried hard to preserve what people liked about both ScalaTest and Scalactic: that it is simple, the code is clean and clear, it's fully documented, and because of very thorough testing, it “just works.”

For information on how to include ScalaTest in your project, see the Install page. For information on how to use Scalactic in your production code, see its Install page.

Highlights

The most significant enhancement to ScalaTest and Scalactic in the 3.0.0 release is that they now fully support Scala.js. The advent of Scala.js represented a major, completely unforeseen change in requirements for ScalaTest. As a result, Scala.js support required a very large number of changes to the ScalaTest's eight-year old codebase. Fortunately, the changes were mostly internal to ScalaTest, so little existing ScalaTest user code (i.e., for Scala on the JVM) should break because of the addition of Scala.js support.

ScalaTest and Scalactic 3.0.0 include a few changes that could in theory break 2.2.x user code, but we expect the number of users and amount of code affected to be small in practice. However, because features that have been deprecated for at least a year (primarily features that were deprecated in October 2013, when 2.0.0 was released) have been removed, we recommend you clear any deprecation warnings given by ScalaTest and Scalactic version 2.2.6 prior to upgrading. For many users, upgrading to ScalaTest and/or Scalactic 3.0.0 should require only a clean build with the new version. ScalaTest 3.0.0 does include several new deprecations as well as the deprecation expirations. For more detail, see the breaking changes, new deprecations, and the expired deprecations sections below.

Here's a list of the main enhancements in Scalactic 3.0.0:

  • Added support for Scala.js.
  • Added org.scalactic.exceptions.NullArgumentException, and changed all places in ScalaTest and Scalactic that threw NullPointerException in earlier releases to throw NullArgumentException. Although throwing NullPointerException is the tradition in Java APIs, Scala.js does not support a NullPointerException. To make the behavior consistent on both the JVM and Scala.js, the change to throwing NullArgumentException was made throughout the ScalaTest and Scalactic, including the requireNonNull method of trait Requirements.
  • Positive numeric types, such as PosInt, PosZInt, PosFloat, etc., have been added in package org.scalactic.anyvals along with CompileTimeAssertions, which you can help you create your own restricted value AnyVal types.
  • Renamed Constraint to CanEqual and made a deprecated type alias for any user code currently referring to Constraint.
  • Made Chain an AnyVal that wraps List instead of an AnyRef. Dropped its inheritance relationship with PartialFunction.
  • Dropped unused type parameter in Good and Bad, specifying Nothing for that now missing type parameter when extending Or. This is a breaking change, but one which hopefully won't affect much client code in practice.
  • Added a validating method to TrySugar, and added FutureSugar also with a validating method. Also added ValidationFailedException to support these validating methods as well.
  • Added Position that supports capturing of caller's source code position through macro.
  • Ensured that Or, Every, and Validation extended both Product and Serializable to improve type inference.

Here's a list of the main enhancements in ScalaTest 3.0.0:

  • Added support for Scala.js.
  • Added type org.scalatest.compatible.Assertion to serve as the actual type required by test bodies in the new async styles. Eventually this will be released as a separate Java artifact, just a simple marker interface, so third-party libraries can provide assertions that ScalaTest will recognize as valid assertions without requiring the third party libraries depend on a version of ScalaTest. They will only need to depend on a version of the scalatest-compat.jar Java artifact, which will be very stable.
  • Defined org.scalatest.Assertion as a type alias for the newly added marker interface, org.scalatest.compatible.Assertion.
  • Changed the result type of assertions and matcher expressions from Unit to Assertion.
  • Changed the result type of org.scalatest styles from Unit to Any so that users who compile with -Ywarn-value-discard will not get warnings for tests that end in an assertion or matcher expression, which no longer has a Unit result type.
  • Added "async" testing styles—AsyncFunSuite, AsyncFunSpec, AsyncFlatSpec, AsyncFreeSpec, AsyncWordspec, and AsyncFeatureSpec—in which the result type of tests is Future[Assertion]. All asynchronous style traits mixed in RecoverMethods that contains recoverToExceptionIf for asynchronous use case for intercept and recoverToSucceededIf for asynchronous use case for assertThrows.
  • Added overloaded exists and forEvery methods to TableDrivenPropertyChecks. exists succeeds if at least one row of the table satisfies the assertion block. forEvery requires that all rows of the table satisfy the assertion block, like forAll, but reports information about all rows that fail the assertion block (where forAll just reports the first row that fails and short circuits).
  • Enhanced ScalaTest Matchers with oneElementOf, noElementsOf, atLeastOneElementOf, atMostOneElementOf, allElementsOf, inOrderElementsOf syntax, all of which must follow contain.
  • Modified ScalaTest's BeforeAndAfterEach and BeforeAndAfter so that it will interact properly and consistently when mixed in either before and after OneInstancePerTest.
  • In 2.x releases of ScalaTest, the ScalaTest JAR file included a copy of the Scalactic library, which ScalaTest uses. In 3.0.0 the ScalaTest JAR file contains only ScalaTest, and has a required dependency on Scalactic. 3.0.0 includes a new artifact, scalatest-app, which includes both ScalaTest and Scalactic. The purpose of scalatest-app is to suppose ScalaTest being run as an application, such as on the Quick Start page.
  • Added implicit parameters of type Prettifier to Assertions, Matchers, and other classes that produce error messages. This makes it easy to customize the string representation of a type in an error message, for example, to reduce the size of string representations of large collections.
  • Added implicit parameters of type source.Position to Assertions, Matchers, and other classes that produce error messages. This allowed us to replace the JVM-specific technique we used previously to determine the file name and line number of the offending line of test code prior to 3.0, which involved inspecting the stack. This technique did not work at all when running Scala.js tests on Node.js or Phantom.js, and allows us on the JVM to access an additional piece of information that wasn't available when inspecting the stack: the full path to the source file. The full path was desired for Ensime and will eventually make it out to the reporters (we didn't have time to get it to the reporters in 3.0.0). This also makes it very simple for users to define custom assertions and get the right stack depth (really, the right filename and line number). We've wanted to solve that problem for a very long time, and users have occasionally requested it. For example, it was requested for the scalaz-scalatest library that created custom ScalaTest assertions for Scalaz.
  • Added optional string failedCodeFilePathname field to StackDepth, which is mixed into "stack depth exceptions." Changed all stack depth exceptions (subclasses of StackDepthException and JUnitTestFailedError) so that the constructor takes either a Position or a stack depth function: Either[Position, StackDepthException => Int]. In most situations a Position will now be available, and it will be passed to the constructor. But in some situations a Position cannot be used and the old approach of using a stack depth function to find the failing line of source code will still be used. be used instead of a
  • Added optional string filePathname field to LineInFile to allow the full path name of the source file that is provided by Position to be passed to reporters.
  • Added a V option to string reporters (e.g., -oV) in Runner and ScalaTest's sbt Framework implementation that causes the string reporters to print the full path name to the source file containing the failing line of code instead of just the simple file name. This makes it easier for ENSIME to allow text editors (such as Emacs, Vim, or Sublime) to click and hop to the failing line of code.
  • Ensured that Outcome, PatienceConfigParam, Event, Formatter, Location, PropertyCheckConfigParam, Query, and Units extended both Product and Serializable to improve type inference.

Breaking changes

1) The main breaking change in Scalactic in 3.0.0 is that we dropped an unnecessary type parameter in Good and Bad, specifying Nothing for that now missing type parameter when extending Or.

2) Because we started using Prettifier as an implicit type in 3.0, we dropped its inheritance relationship with Any => String (so that an implicit Prettifier won't be usable as in implicit conversion from Any to String). It is unlikely anyone was actually using Prettifier as a Function1, but if so, that will no longer compile and you'll need to convert it to Any => String explicitly.) Furthermore, since Prettifier was now being used as an implicit itself, we changed PrettyMethods to require an implicit Prettifier instead of a PrettifierConfig. Thus if you defined an overridden implicit PrettifierConfig, that will no longer compile, and you'll need to replace it with an implicit Prettifier instead. For a quick fix, we left the old PrettyMethods behavior in under the name DeprecatedPrettyMethods. If you just change PrettyMethods to DeprecatedPrettyMethods, that will get your PrettifierConfig code compiling and working again, but you'll receive a deprecation warning until you replace the PrettifierConfig with Prettifier, and DeprecatedPrettyMethods with PrettyMethods.

3) In ScalaTest, one potentially breaking change is in TimeLimitedTests, which now uses an implicit Signaler instead of an implicit Interruptor. Whereas the default Interruptor in TimeLimitedTests prior to 3.0 was a ThreadInterruptor, the default signaler is DoNotSignal. This default makes more sense with the advent of ScalaTest 3.0's support for Scala.js and async testing styles. If you were relying on the default behavior of interrupting a thread on the JVM in ScalaTest 2.2.x, you'll need to define an implicit val referring to a ThreadSignaler. If you had alreday overriden the default Interuptor (referenced from defaultInterruptor) you'll need to define a corresponding Signaler instead (unless you had defined the Interruptor to be DoNotInterrupt, in which case you can just remove the defaultInterruptor override entirely and enjoy the default Signaler, DoNotSignal).

4) In 3.0.0, the withFixture method has been moved from Suite to a new trait, TestSuite. This was done to make room for a withFixture method with a different signature in AsyncTestSuite. If you factored out a withFixture method into a separate "suite mixin" trait, you'll need to change "Suite" to "TestSuite" and "SuiteMixin" to "TestSuiteMixin". For example, given this trait from 2.2.6:

trait YourMixinTrait extends SuiteMixin { this: Suite =>
 abstract override def withFixture(test: NoArgTest): Outcome = {
   // ...
 }
}

You will need to add the "Test" prefix, like this:

trait YourMixinTrait extends TestSuiteMixin { this: TestSuite =>
 abstract override def withFixture(test: NoArgTest): Outcome = {
   // ...
 }
}

5) In ScalaTest we changed the signature of the whenCompleted method of trait Status changed. Where it previously took a function of type Boolean => Unit, it now takes a function of type Try[Boolean] => Unit. This breaking change should affect very few users.

6) Lastly, because the result type of assertions and matcher expressions has changed from Unit to Assertion, any tests in JUnitSuite, JUnit3Suite, and TestNGSuites that ended with an assertion or matcher expression, and used neither the (now deprecated) procedure style "...@Test def theTestName() {..." nor an explicit type annotation, "...@Test def theTestName(): Unit = {...", will no longer be recognized by those frameworks. These test frameworks require that the result type of test methods be void in Java, which equates to Unit in Scala.

Only JUnitSuite, which is based on JUnit 4, will indicate with a test failure that a method annotated with @Test did not have result type void. You will get a test failure with an error message like:

java.lang.Exception: Method verifySomething() should be void

By contrast, any such tests in JUnit3Suite and TestNGSuite will be silently ignored by JUnit 3 and TestNG. To get the tests running again in any of these styles, ensure an explicit result type is placed on each test method, like:

@Test def verifySomething(): Unit = {
  val x = 1
  assert(x == 1)
}

If this change has a significant impact on your project, please contact Artima by emailing Bill Venners at bill AT artima.com. We are happy to help you upgrade your JUnitSuite, JUnit3Suite, or TestNGSuite, tests to ScalaTest 3.0.

New deprecations

  • Deprecated ConversionCheckedTripleEquals, because code that is using it can still compile but mean something quite different if it is removed.
  • Deprecated the parameterless execute method on Suite. Please use the empty parens version instead: execute().
  • Deprecated the withGood method on the org.scalactic.Accumulation object that takes one Or and one transformation function. Please call map on the Or and pass in the same function instead.
  • Deprecated the asOr method on Or, because its main use case is now obsolete, since Good(value).orBad[Type] and Good[Type].orBad(value) now return Or. You can simply remove asOr invocation from such expressions, or if used elsewhere, replace it with a widening type annotation, such as: (hasTypeGood: Int Or ErrorMessage).
  • Deprecated org.scalactic.Constraint. Please change any occurrences to its new name, CanEqual. (Constraint should appear explicitly in user code only very rarely if at all, as normally it will be used only implicitly.)
  • Added an already deprecated implicit conversion to the Filter companion object because the inheritance relationship between Filter and Function2[Set[String], Map[String, Set[String]], List[(String, Boolean)]] was removed.
  • Deprecated PropertyCheckConfig in favor of PropertyCheckConfiguration in object org.scalatest.prop.Configuration. The new class uses org.scalactic.anyvals and instead of an absolute maxDiscarded value, calculates that value by multiplying a maxDiscardFactor by the minSuccessful value.

Expired deprecations

  • Removed the before/afterEach(TestData) methods in BeforeAndAfterEach (deprecated in ScalaTest 2.0) in favor of BeforeAndAfterEachTestData.
  • Removed org.scalatest.FailureOf (deprecated in ScalaTest 2.0) in favor of OutcomeOf.
  • Removed expect and expectResult (deprecated in ScalaTest 2.0) in Assertions in favor of assertResult.
  • Removed the support for using Suite as a style trait (deprecated in ScalaTest 2.0) in favor of Spec (which itself was deprecated in 3.0.0 and renamed org.scalatest.refspec.RefSpec.)
  • Removed the assert and assume methods whose === and !== operator return Option[String] (deprecated in ScalaTest 2.0) in favor of assert and assume macros that return Boolean.
  • Removed the plusOrMinus (deprecated in ScalaTest 2.0) operator used with Matchers in favor of the +- symbol.
  • Removed ShouldMatchers (deprecated in ScalaTest 2.0) and MustMatchers (deprecated in ScalaTest 1.9.2), both members of package org.scalatest.matchers, in favor of Matchers, and MustMatchers, which resides in package org.scalatest.
  • Removed the beforeAll and afterAll methods of trait BeforeAndAfterAll that take a config map (deprecated in ScalaTest 2.0) in favor of BeforeAndAfterAllConfigMap.
  • Removed given/when/then/and methods of trait GivenWhenThen (deprecated in ScalaTest 2.0) in favor of capitalized forms, Given/When/Then/And, because then was deprecated as an identifier in Scala 2.10.
  • Removed the two original apply methods on Filter (deprecated in ScalaTest 2.0), in favor of two new ones added in ScalaTest 2.0 that take an additional suiteId parameter.
  • Removed trait AbstractSuite (deprecated in ScalaTest 2.0) in favor of trait SuiteMixin, which since 2.0 has served as the base class for stackable traits that can be mixed into Suite.
  • Removed the original apply method on Distributor (deprecated in ScalaTest 2.0) in favor of the apply method added in 2.0 that takes a Args.

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-2016 Artima, Inc. All Rights Reserved.

artima