Migrating from ScalaTest 1.x to 2.0
We have always worked very hard to maintain source compatibility from one release of ScalaTest to the next. Upgrading is usually simply a matter of bumping
the ScalaTest version number in your build doing a full recompile, and over time cleaning up any deprecation warnings. With ScalaTest 2.0, however,
we made some improvements for which it was not possible to deprecate, so some of your existing code may not compile. Neverthless, we expect the vast
majority of existing ScalaTest user code to just recompile as is.
To ensure the smoothest migration, first please eliminate any deprecation warnings
being emitted by your current version of ScalaTest on your existing code. (For best results, upgrade to 1.9.2 first and clear any deprecation warnings, though
many of those reported will still be deprecated and working in 2.0.) Then just bump the ScalaTest version number to 2.0 and do a full build.
If you encounter compilation errors, check the list below for help in resolving them.
These are the points of potential breakage in ScalaTest 2.0, which are described in the sections that follow:
- Custom
Reporter
s (rare, but requires some rewriting)
withFixture
methods (common, but easy to fix)
run
method signatures (rare and easy to fix)
List
to immutable.IndexedSeq
(extremely rare, easy to fix)
length
, size
and HavePropertyMatcher
s (extremely rare, easy to fix)
- Style classes (rare, easy to fix)
- The fragile base class problem (occasional, usually easy to fix)
If you have any confusion about how to migrate your ScalaTest 1.x code to ScalaTest 2.0, or encounter other problems, please post your specific issues
to scalatest-users
and we'll be happy to help.
Custom Reporter
s
We greatly enhanced ScalaTest's event model in 2.0 to improve tools integration and reporting. Because it is not possible in Scala to deprecate
extractors, custom Reporter
s written for ScalaTest 1.x will usually
need to be migrated. You still write custom Reporters
in 2.0 the same way as in 1.x: you implement
apply
and handle events, usually by pattern matching on them. In 2.0, however, more events exist, and several of the pre-existing events now have more fields in them
(though all the old fields still exist and mean the same thing). So if an existing pattern match no longer compiles, look at the event (located in package
org.scalatest.events
) and make necessary changes to your pattern to accomodate the
new structure of the event. You may also want or need to handle events newly added in ScalaTest 2.0. For a nice list of all the 2.0 events, with links to the appropriate
Scaladoc documentation, see the main documentation for Reporter
.
withFixture
methods
In 2.0, the withFixture
methods declared in
Suite
and fixture.Suite
, and the
NoArgTest
and OneArgTest
functions passed to them, now
return an Outcome
. Because withFixture
previously
returned Unit
, you will need to insert an =
before the open curly brace of your overridden withFixture
implementations if you
didn't already do so, and in some cases, : Outcome =
.
I.e., change a withFixture
like this:
override def withFixture(test: NoArgTest) {
setupDb()
try super.withFixture(test)
finally cleanupDb()
}
To this (by adding the =
sign):
override def withFixture(test: NoArgTest) = {
setupDb()
try super.withFixture(test)
finally cleanupDb()
}
That will most often be all that's required, but if you were catching exceptions in a
withFixture
implementation, you will likely also need to change your catch clauses to a corresponding pattern match
on Outcome
types.
I.e., change a catch clause like this one:
override def withFixture(test: NoArgTest) {
try super.withFixture(test)
catch {
case ex: Throwable =>
throw ex
}
}
To a corresponding pattern match on Outcome
:
override def withFixture(test: NoArgTest) = {
val outcome = super.withFixture(test)
outcome match {
case Failed(ex) =>
}
outcome
}
run
method signatures
We modified the signature of four of Suite
's lifecycle methods: run
,
runNestedSuites
, runTests
, and runTest
. First, to make these methods more pleasant to override, we gathered
the parameters common to these methods into an Args
value object. If you have previously overridden them, you'll need to change
the method signature. Because the parameters have the exact same name inside the Args
object, however, you can simply import args._
to get them back in scope in your existing code.
For example, you'd change an overridden method like this:
override def runTests(testName: Option[String], reporter: Reporter,
stopper: Stopper, filter: Filter, configMap: Map[String, Any],
distributor: Option[Distributor], tracker : Tracker) {
}
To this:
override def runTests(testName: Option[String], args: Args): Status = {
import args._
}
By importing the members of args
, all the parameter names in scope before—reporter
, stopper
, etc.—will
again be in scope. Note that invocations of methods using the old signatures will also need to be changed to use the new signatures.
In addition to collecting parameters in Args
, we changed the result type from Unit
to
Status
. A Status
is
like a Future[Boolean]
that ultimately will indicate whether any failed test or aborted suite occurred. The Status
``completes''
when the tests and/or nested suites started by that method have all completed. Thus you may also need change your code so that an appropriate
Status
is returned. If so, familiarize yourself with the convenience Status
subclasses:
SuccceededStatus
,
FailedStatus
,
StatefulStatus
,
and CompositeStatus
.
Here's an example overriden runTests
method that cancels an entire suite of tests if its Selenium
driver is not supported. If the driver is supported, it just invokes super.runTests
and returns the
resulting Status
. Otherwise it fires an alert message and returns SucceededStatus
. (A succeeded Status
doesn't necessarily mean
that any tests ran, just that no test failed and no suite aborted.)
abstract override def runTests(testName: Option[String], args: Args): Status = {
if (driverSupported)
super.runTests(testName, args)
else {
alert("Cancelling " + this.suiteName + " : " + browserType + " not installed")
SucceededStatus
}
}
List
to immutable.IndexedSeq
Where List
appeared as a result type in ScalaTest 1.x, immutable.IndexedSeq
is used instead in ScalaTest 2.0; for example, the result type of Suite
's nestedSuites
lifecycle method.
(Under the covers we return a Vector
.) When ScalaTest 1.0 was initially released, Vector
did
not yet exist in the Scala library and List
was considered by many to be the default Seq
type to use. In practice, it was discovered that
it is too easy to use List
(and other LinearSeq
's) in a non-performant way. In 2.0 we wanted to take the opportunity to make the
potentially breaking change of replacing List
result types with immutable.IndexedSeq
. This potentially breaking change is expected
to affect very little, if any, user code, essentially only code that called nestedSuites
then used ::
or :::
operators
on the result. To fix such a break, use +:
instead of ::
and ++
instead of :::
.
length
, size
and HavePropertyMatcher
s
Although ScalaTest's matchers have undergone a major refactor in 2.0, all previously documented syntax for matchers should continue to work exactly
the same with one potential exception, which should in practice be extremely rare. The potential breakage is that if you included length
or size
along with custom have-property matchers that you wrote, you'll get a compiler error. To fix such an error, add after
your length
or size
invocation an (of [<type>])
clause, as
described in the main Scaladoc documentation for Matchers
.
Style classes
In ScalaTest 1.9.2, we refactored each style trait into a style class/style trait pair, to obtain speedier compiles. For example, in ScalaTest 1.9.1 and prior
versions, FlatSpec
was
a trait. In 1.9.2 and 2.0, FlatSpec
is a class; FlatSpecLike
is the trait. Same for FunSuite
(now a class) FunSuiteLike
(now the trait), and so on. Usages that directly extend a style trait will continue
to work fine (but should compile slightly faster). For example, this will continue to compile as before:
class MySpec extends FlatSpec with Matchers {
}
However, if you were mixing in a style trait after with
, you'll need to add Like
. For example, you'd need to change this:
class MySpec extends TestKit(ActorSystem("my actors"))
with FlatSpec with Matchers {
}
To this (by adding “Like
” to FlatSpec
):
class MySpec extends TestKit(ActorSystem("my actors"))
with FlatSpecLike with Matchers {
}
The fragile base class problem
To our knowledge, the only other source of potential breakage in ScalaTest 2.0 is the fragile base class problem. We have added fields and methods to traits such as
Matchers
and Suite
in 2.0 that may
conflict with fields and methods in your existing classes and cause a compiler error. Such issues can usually be easily fixed locally with simple renames or refactors.