I created the following fixtures:
trait DatabaseFixture extends TestSuiteMixin { this: TestSuite =>
// Just setting up a test database
val cpds = new ComboPooledDataSource
val url : URL = getClass.getResource( "c3p0.properties" )
val db = Database.forDataSource(cpds, Some(50))
val users = Schema.users
val instances = Schema.instances
Await.result(db.run( DBIO.seq(
users.schema.create,
) ), 3 seconds )
abstract override def withFixture(test: NoArgTest): Outcome = {
try super.withFixture(test)
finally cpds.close()
}
}
trait UserControllerFixture extends DatabaseFixture with ScalatraSuite { this: TestSuite =>
addServlet( new UserController(db), "/user/*" )
abstract override def withFixture(test: NoArgTest): Outcome = {
super.withFixture( test )
}
}
Here is the first way I mixed them in to a test suite:
class UserControllerTestSuite extends DatabaseFixture with ScalatraSuite with FlatSpecLike with Matchers {
"POST to /user/add" should "return 201 for created" in {
post( "/instance/add" ) {
status shouldBe 201
}
}
}
This failed to compile with the following error: method withFixture in trait TestSuite of type (test: UserControllerTestSuite.this.NoArgTest)org.scalatest.Outcome has weaker access privileges; it should be public
However, when I mixed the fixtures in after the other scalatest traits, it compiled fine:
class UserControllerTestSuite extends ScalatraSuite with FlatSpecLike with Matchers with DatabaseFixture {
"POST to /user/add" should "return 201 for created" in {
post( "/instance/add" ) {
status shouldBe 201
}
}
}
What's going on here? What does it mean that withFixture() has "weaker access privileges"?
Mixins in Scala are scanned right to left. This is why DatabaseFixture is called before other traits in case where your code works.
So before when there was some other trait (TestSuite) before DatabaseFixture with withFixture method , it tried to override it "weaker access privilege", which means exactly what it says. You cannot override public method with private for example. It has to be the same priority or higher (public > protected in your case.)
First off, I saw it and this other post sounds exactly like what I need except for one thing, I can't use fixture.TestDataFixture because I can't extend fixture.FreeSpecLike, and I am sure that there must be some way to get the test name in a way that looks more like this (imagined code that doesn't compile)
class MySpec extends FlatSpecLike with fixture.TestDataFixture {
"this technique" - {
"should work" in {
assert(testData.name == "this technique should work")
}
"should be easy" in { td =>
assert(testData.name == "this technique should be easy")
}
}
}
Any ideas? I just can't believe something like this is not possible :D
While you already came to basically this solution, here is a safer variation:
private val _currentTestName = new ThreadLocal[String]
override def withFixture(test: NoArgTest) = {
_currentTestName.set(test.name)
val outcome = super.withFixture(test)
_currentTestName.set(null)
outcome
}
protected def currentTestName: String = {
val testName = _currentTestName.get()
assert(testName != null, "currentTestName should only be called in a test")
testName
}
Alternately,
protected def currentTestName = Option(_currentTestName.get())
You can find sequence of test names using method testNames in FlatSpecLike trait:
import org.scalatest.FlatSpecLike
class FooSpec extends FlatSpecLike {
it should "check case one" in {
println("test some code ...")
println(testNames.mkString("\n"))
/*
prints:
should check case one
should check case two
*/
// ...
assert(1 == 1)
println("end.")
}
it should "check case two" in {
println("test some code ...")
assert(1 == 1)
println("end.")
}
}
and find each you needed. Hope it helps.
And found an answer(well a collegue did), not sure I like it but works:
on the trait that other tests depend on
class MySpec extends FlatSpecLike {
//... other stuff
var testName = "UndefinedTestName"
override def withFixture (test: NoArgTest) :Outcome= {
testName = test.name
super.withFixture(test)
}
}
simple solution but rather obscure, also I wonder if anyone sees any problems with it
I've been noticing a lot of repetition to set up each test with Play/specs2. I'm aware that you can create a trait that extends mutable.Before and use that to set up tests but any values created there seem to be out of scope for my tests.
What I would like to be able to do is set val user = User.create("User Name") in a class or trait before each test runs so I can have access to user later on in the test. How can this be achieved?
// SpecificationWithFixtures.scala
package models
import org.specs2.execute.{AsResult, Result}
import org.specs2.mutable._
import play.api.test.Helpers._
import play.api.test._
abstract class SpecificationWithFixtures extends Specification {
abstract class WithFakeDB extends WithApplication(FakeApplication(additionalConfiguration = inMemoryDatabase())) {
override def around[T: AsResult](t: => T): Result = super.around {
t
}
}
}
// UserSpec.scala
package models
import org.junit.runner._
import org.specs2.runner._
#RunWith(classOf[JUnitRunner])
class UserSpec extends SpecificationWithFixtures {
"User.create" should {
"save user in the database" in new WithFakeDB {
val user = User.create("User Name")
// Some test for user
}
}
"User.findAll" should {
"return a list of all users" in new WithFakeDB {
val user = User.create("User Name")
// Another test for user
}
}
}
What you can do is something like:
def withUser[T](test: User => T): T = test(User create "Username")
// or even more configurable
def withUser[T](name: String)(test: User => T): T = test(User create name)
// Then writing expectations you can do
"User Roger" in withUser("Roger") {
roger => // trivial example
roger.name must_== "Roger"
}
// or even
"User" in withUser("John") {
_.name must_== "John"
}
This kind of loan pattern is useful writing specs2.
In previous example it's user per expectation (in), but it can be used for a group of expectations (should, >>), or for all.
"User" should withUser("xyz") {
"exp1" in { ??? }
}
Is it possible to access the name of the currently executing test, from within a ScalaTest test? (And how would I do it?)
Background:
I'm testing that my Data Access Object eventually throws an OverQuotaException if a user e.g. creates too many pages. These tests take rather long to run. To feel happier, I'd like to print the progress to stdout — and since there are quite many tests, I'd like to include the test name in the output, so I know what test is currently being run.
(I didn't find any seemingly relevant function here: http://www.artima.com/docs-scalatest-2.0.M5/#org.scalatest.FreeSpec )
Example:
"QuotaCharger can" - {
"charge and decline quota consumers" - {
"charge a per site IP number (guest user)" in {
// ... Here, a guest user post very many comments until it's over quota.
// This takes a little while, and there are many similar tests.
// ---> Here <--- I'd like to access the string:
// "charge a per site IP number (guest user)",
// is that possible somehow?
}
The intended way to do that is to override withFixture and capture the test data. In this use case, it is better to override withFixture in fixture.FreeSpec so you can pass the test data into each test rather than using a var. Info on that is here:
http://www.artima.com/docs-scalatest-2.0.M5/org/scalatest/FreeSpec.html#withFixtureNoArgTest
When I saw your question this morning I realized ScalaTest should have a trait that does this, so I just added one. It will be in 2.0.M6, the next milestone release, but in the meantime you can use a local copy. Here it is:
import org.scalatest._
/**
* Trait that when mixed into a <code>fixture.Suite</code> passes the
* <code>TestData</code> passed to <code>withFixture</code> as a fixture into each test.
*
* #author Bill Venners
*/
trait TestDataFixture { this: fixture.Suite =>
/**
* The type of the fixture, which is <code>TestData</code>.
*/
type FixtureParam = TestData
/**
* Invoke the test function, passing to the the test function to itself, because
* in addition to being the test function, it is the <code>TestData</code> for the test.
*
* <p>
* To enable stacking of traits that define <code>withFixture(NoArgTest)</code>, this method does not
* invoke the test function directly. Instead, it delegates responsibility for invoking the test function
* to <code>withFixture(NoArgTest)</code>.
* </p>
*
* #param test the <code>OneArgTest</code> to invoke, passing in the
* <code>TestData</code> fixture
*/
def withFixture(test: OneArgTest) {
withFixture(test.toNoArgTest(test))
}
}
You would use it like this:
import org.scalatest._
class MySpec extends fixture.FreeSpec with TestDataFixture {
"this technique" - {
"should work" in { td =>
assert(td.name == "this technique should work")
}
"should be easy" in { td =>
assert(td.name == "this technique should be easy")
}
}
}
Create your own trait, let say RichFreeSpec.
trait RichFreeSpec extends Free {
protected final class RichFreeSpecStringWrapper(name: scala.Predef.String) {
def in(f: String => scala.Unit) {
def f2 = f(name)
new WordSpecStringWrapper(string).in(f2)
}
}
protected implicit def convertToRichFreeSpecStringWrapper(n: scala.Predef.String): = {
new RichFreeSpecStringWrapper(n)
}
}
Than just use:
"sth" in { testName =>
...
}
Of course, you can go further and implement the full name hierarchy.
You can use BeforeAndAfterEachTestData for what you need.
If you need access to the test case name in the beforeEach or afterEach method.
class MyTestSuite with AnyFunSuiteLike with BeforeAndAfterEachTestData {
override def beforeEach(testData: TestData): Unit = {
testData.name // do whatever.
super.beforeEach(testData)
}
}
If you need access to the test case name in the test case itself, then you can use a thread local approach
private val currentTestCaseName = new ThreadLocal[String]
override def beforeEach(testData: TestData): Unit = {
currentTestCaseName.set(testData.name)
super.beforeEach(testData)
}
test("fancy test") {
currentTestCaseName.get() // do whatever
}
Here's a solution. Extend this class instead of FreeSpec. License: CC0.
Edit: This doesn't work with concurrent tests though.
(The difference between this approach and the other answer, is that 1) here there's a currentTestName field, and in the other answer the test name is passed to the test body, and 2) this test name includes all test branch names concatenated + the actual test name, whereas the other answer's test name is exactly the test name (without test branch names).)
(Ooops, you'd need to use getOrElse ... instead of my lovely getOrDie.)
/**
* Adds a field `currentTestName` that you can use inside a FreeSpec test,
* if you for example have many tests that take rather long, and you wonder
* which one is currently running.
*/
trait RichFreeSpec extends FreeSpec {
private var _currentTestName: Option[String] = None
def currentTestName = _currentTestName getOrDie "DwE90RXP2"
protected override def runTest(testName: String, args: org.scalatest.Args) {
_currentTestName = Some(testName)
super.runTest(testName, args)
}
}
If the intent is to be able to access the test name from anywhere, as was suggested by #kajmanus in previous comments, a ThreadLocal fits the bill nicely.
You could define a case class to store the info you require for the current test context. e.g.,
case class TestContext(name: Option[String] = None)
object TestContext {
val currentTest: ThreadLocal[TestContext] =
ThreadLocal.withInitial(() => TestContext())
}
Then define a trait your various specs will extend. e.g.,
trait BaseFunSpec
extends AnyFunSpec
...
{
override protected def withFixture(test: NoArgTest): Outcome = {
try {
TestContext.currentTest.set(TestContext(name = Some(test.name)))
super.withFixture(test)
} finally {
TestContext.currentTest.remove()
}
}
}
Finally, you can access the current test context you've set for the current thread (which in this example is purely the test name) from anywhere within the current thread as needed. e.g.,
def cachedResults(bytes: Array[Byte], fileType: String): Unit = {
TestContext.currentTest.get().name match {
case Some(testname) =>
import scala.util.Using
val file = new File("target", s"${testname}.${fileType}")
Using(new BufferedOutputStream(new FileOutputStream(file))) { os =>
os.write(bytes)
}
case None => throw new IllegalStateException("Unknown test context")
}
}
This will work whether you're running tests in parallel or not, assuming you're not processing things asynchronously (i.e., in another thread).
A cleaner usage of this is to create purposed actors. e.g.,
case class TestContext(name: Option[String] = None)
object TestContext {
val currentTest: ThreadLocal[TestContext] = ThreadLocal.withInitial(() => TestContext())
class TestNamer {
def currentName: String = currentTest.get().name match {
case Some(testname) => testname
case None => throw new IllegalStateException("No test context available")
}
}
class TestContextWriter(testNamer: TestNamer = new TestNamer()) {
def cachedBytes(bytes: Array[Byte], extension: String): Array[Byte] = {
import java.io.{BufferedOutputStream, File, FileOutputStream}
import scala.util.Using
val file = new File("target", s"${testNamer.currentName}.${extension}")
Using(new BufferedOutputStream(new FileOutputStream(file))) { outstream =>
outstream.write(bytes)
}
bytes
}
}
}
And inject as needed:
trait BaseFunSpec {
val testContextWriter = new TestContextWriter()
def fetchRawResults(...): Array[Byte] = {
...
testContextWriter.cachedBytes(bytes, "pdf")
}
}
Suppose I have a specs2 specification defined in the "unit" style as follows:
import org.specs2.mutable
class MyClassSpec extends mutable.Specification {
"myMethod" should {
"return positive values" in {
MyClass.myMethod must beGreaterThan(0)
}
"return values less than 100" in {
MyClass.myMethod must beLessThan(100)
}
}
}
Is there an easy way to skip/disable/mark pending all of the examples within the should block/fragment for myMethod?
Obviously I can call pendingUntilFixed or return pending from each individual example in the block, but this would be rather tedious for a block with many specifications.
It seems like this would be a common occurrence if MyClass.myMethod is difficult to implement and gets punted. Is there another way that this is commonly done in specs2?
You can mix in the Tags trait and define any section you want:
import org.specs2.mutable._
class MyClassSpec extends Specification with Tags {
section("pending")
"myMethod" should {
"return positive values" in {
MyClass.myMethod must beGreaterThan(0)
}
"return values less than 100" in {
MyClass.myMethod must beLessThan(100)
}
}
section("pending")
}
Then you run your specification with exclude pending
>test-only *MyClassSpec* -- exclude pending
This is documented here.
You can also use an implicit context to make sure that all your examples in the should block are PendingUntilFixed:
import org.specs2._
import execute._
class MyClassSpec extends mutable.Specification {
"this doesn't work for now" >> {
implicit val puf = pendingContext("FIXME")
"ex1" in ko
"ex2" in ok
}
"but this works ok" >> {
"ex3" in ko // maybe not here ;-)
"ex4" in ok
}
def pendingContext(reason: String) = new mutable.Around {
def around[T <% Result](t: =>T) =
t.pendingUntilFixed(reason)
}
}
Update for specs2 3.x
import org.specs2._
import execute._
class TestMutableSpec extends mutable.Specification {
"this doesn't work for now" >> {
implicit def context[T] = pendingContext[T]("FIXME")
"ex1" in ko
"ex2" in ok
}
"but this works ok" >> {
"ex3" in ko // maybe not here ;-)
"ex4" in ok
}
def pendingContext[T](reason: String): AsResult[MatchResult[T]] =
new AsResult[MatchResult[T]] {
def asResult(t: =>MatchResult[T]): Result =
AsResult(t).pendingUntilFixed(reason)
}
}