ScalaTest test name without fixture? - scala

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

Related

How to initialize fixture once for all tests in scalatest?

According to documentation, fixtures can be passed to tests like this:
def withFixture(test: OneArgTest) = {
val f = veryLengthyInitialization(test.configMap)
withFixture(test.toNoArgTest(f))
}
describe("Some test") {
it("should succeed") { f =>
f.doSomething()
// ...
}
// many other tests
// ...
}
Problem is that the initialization is run for each test, and it takes a very long time, so I would like it to run just once. Documentation suggests an alternative:
override def beforeAll(configMap: ConfigMap) {
val fOnce = veryLengthyInitialization(configMap)
// but how do I pass f to the tests?
// ugly workaround:
f = fOnce
}
var f: InitType = null
describe("Some test") {
it("should succeed") { // hack: no parameter, use var instead
f.doSomething()
// ...
}
// many other tests
// ...
}
It works, but my understanding is that null should be avoided, and it's a bit silly to rely on mutation for something as basic as this. What is the correct way to write such tests?
I don't think that there is a solution that is good in all aspects for this issue. One thing I do sometime to avoid the var is structuring the test as follows:
class SomeTest extends Spec {
def initFixtures(): SomeFixtureType = ???
lazy val fixtures = initFixtures()
describe("Some test") {
it("should succeed") in {
fixtures.doSomething()
// ...
}
}
}
In this way I don't need to use the beforeAndAfterAll thing, but you can if you want to guarantee that the fixtures are initialised before the test as follows:
override def beforeAll() {
super.beforeAll()
fixtures
}
It can also be handy when dealing with asynchronous initialisation since you could have something like:
class SomeTest extends Spec {
def initFixtures(): Future[SomeFixtureType] = ???
lazy val fixtures = initFixtures()
describe("Some test") {
it("should succeed") in {
whenReady(fixtures.flatMap {
f.doSomething()
// ...
}) { res => doSomeChecks(res) }
}
}
}
Having both initFixtures and fixtures is most useful in this case as you can have some tests re-initialise the system and act in isolation if they need to do effectful stuffs (e.g. use a database).
I'm not sure if the below is something better:
trait DoSomething {
var f:InitType = _
def doSomething = f.doSomething
}
class MyTestSpec extends DoSomething {
override def beforeAll(configMap: ConfigMap) {
val fOnce = veryLengthyInitialization(configMap)
f = fOnce
}
it("should succeed") {
doSomething()
}
}
For any tests you need a f variable to do something, you could extend the trait and initialize it in your beforeAll methods, in addition, you could even override the doSomething in your test.

Using JUnit #Rule with ScalaTest (e.g. TemporaryFolder)

I would like to be able to use JUnit rules such as TemporaryFolder or other TestRules we have already developed in-house.
What is the best method to accomplish that? I'm aware of JUnitSuite but it doesn't seem to pick up the #Rule annotation.
I would like to use a different ScalaTest suite anyway.
So my questions are:
Are JUnit rules supported by a ScalaTest suit?
If not, is there a library out there which would make using Junit TestRules possible?
If not, how to use JUnit TestRules in Scala tests?
Or is there a more appropriate Scala-specific approach for acomplishing what TemporaryFolder, or, e.g., Stefan Birkner's System Rules provide?
Here's what I tried with JUnitSuite:
class MyTest extends JUnitSuite {
//#Rule
//val temporaryFolder = new TemporaryFolder() // throws java.lang.Exception: The #Rule 'temporaryFolder' must be public.
#Rule
def temporaryFolder = new TemporaryFolder()
#Test
def test: Unit = {
assert(temporaryFolder.newFile() !== null) // java.lang.IllegalStateException: the temporary folder has not yet been created
}
}
You could solve the problem by creating a member field of type TemporaryFolder and returning this field value by the #Rule function.
class MyTest extends JUnitSuite {
val _temporaryFolder = new TemporaryFolder
#Rule
def temporaryFolder = _temporaryFolder
#Test
def test: Unit = {
assert(temporaryFolder.newFile() !== null)
}
}
Here is what I came up based on ScalaTest's documentation on fixtures. Still, I would like to know if there is a better solution.
Loan-fixture method
class LoanFixtureTest extends FunSuite {
def withRule[T <: TestRule](rule: T)(testCode: T => Any): Unit = {
rule(
new Statement() {
override def evaluate(): Unit = testCode(rule)
},
Description.createSuiteDescription("JUnit rule wrapper")
).evaluate()
}
test("my test") {
withRule(new TemporaryFolder()) { temporaryFolder =>
assert(temporaryFolder.newFile() !== null)
}
}
}
Pros: allows applying the rule only to tests where it is needed
Cons: not very elegant usage; clumsy when multiple TestRules are required
Using stackable mixins with withFixture(test: NoArgTest) override
trait TemporaryFolderFixture1 extends SuiteMixin {
this: Suite =>
val temporaryFolder = new TemporaryFolder
abstract override def withFixture(test: NoArgTest) = {
var outcome: Outcome = null
val statementBody = () => outcome = super.withFixture(test)
temporaryFolder(
new Statement() {
override def evaluate(): Unit = statementBody()
},
Description.createSuiteDescription("JUnit rule wrapper")
).evaluate()
outcome
}
}
class StackableTraitFixtureTest extends FunSuite with TemporaryFolderFixture1 {
test("my test") {
assert(temporaryFolder.newFile() !== null)
}
}
Pros: very simple usage, conveniently allows mixing multiple rules in
Cons: requires having a mixin for every rule; rules need to be invoked even for tests that don't need them; rule cannot be used e.g. in BeforeAfterEach#beforeEach()
Overriding withFixture(test: OneArgTest)
trait TemporaryFolderFixture2 {
thisFixture: org.scalatest.fixture.FunSuite =>
type FixtureParam = TemporaryFolder
override protected def withFixture(test: OneArgTest): Outcome = {
val temporaryFolder = new TemporaryFolder()
var outcome: Outcome = null
temporaryFolder(
new Statement() {
override def evaluate(): Unit = {
outcome = withFixture(test.toNoArgTest(temporaryFolder))
}
},
Description.createSuiteDescription("JUnit rule wrapper")
).evaluate()
outcome
}
}
class OneArgWithFixtureTest extends org.scalatest.fixture.FunSuite with TemporaryFolderFixture2 {
test("my test") { temporaryFolder =>
assert(temporaryFolder.newFile() !== null)
}
}
Cons: allows only one TestRule, making in generic to work with any rule instead of just TestRule would require an extra effort
Which one do you like the best?
This worked for me. Based on answer. So annotation will be applied to
to the (synthetic) getter method
import org.junit._
import scala.annotation.meta.getter
class MyTest extends JUnitSuite {
#(Rule #getter)
val tempFolder = new TemporaryFolder
}
Just make sure to use junit version >4.11.

Specs2 - close JDBC connection after each test case

I implemented specs2 specification that looks something like this:
class MySpec extends Specification {
"My database query" should {
"return some results " in {
val conn = createJdbcConn()
try {
// matcher here...
} finally {
conn.close()
}
}
}
This ugly boilerplate is repeated in all my test cases. I have to open (and then close) a new connection for each in.
What is the idiomatic way in Specs2 close resources such as in this case - perhaps using the After (or BeforeAfter) trait to properly close the connection?
Another option is to use the FixtureExample trait introduced in 2.0, to avoid using a variable:
import org.specs2._
import specification._
import execute._
trait DbFixture extends FixtureExample[JdbcConnection] {
// type alias for more concise code
type DBC = JdbcConnection
/**
* open the connection, call the code, close the connection
*/
def fixture[R : AsResult](f: JdbcConnection => R): Result = {
val connection = createJdbcConnection
try AsResult(f(connection))
finally connection.close
}
}
class MySpec extends Specification with DbFixture {
"My database query" should {
"return some results" in { connection: DBC =>
// do something with the connection
success
}
}
}
It might be easiest to use a trait, and then your tests that need a db connection can just extend the trait (I'm not thrilled about the var, but it's the easiest way to do this):
trait DbTestLifeCycle extends BeforeAfterExample {
var dbConn:Option[YourDbConnection] = None
protected def before: Any = {
dbConn = Option(createJdbcConn())
}
protected def after: Any = {
dbConn.map(_.close())
}
}
So your test would look like this:
class MySpec extends Specification with DbTestLifeCycle {
"My database query" should {
"return some results " in {
dbConn.map(conn => //do something in the db)
// matcher here...
}
}
}

Access ScalaTest test name from inside test?

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")
}
}

How can I skip a "should" block/fragment in specs2?

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)
}
}