Reputation: 473
I want to log the unit test names in Scala automatically. The solution with org.junit.rules.TestName
works fine in Java, but not in Scala.
Consider the following code snippet:
import org.junit._
import org.junit.rules.TestName
class ScalaUnitTestExample {
@Rule val testName = new TestName
@Before def printTestCaseNameBefore() {
print("\nStart of test case " + testName.getMethodName)
}
@After def printTestCaseNameAfter() {
print("\nEnd of test case " + testName.getMethodName)
}
@Test
def checkAddition() {
Assert.assertEquals(5, 2 + 3)
}
@Test
def checkMultiplication() {
Assert.assertEquals(6, 2 * 3)
}
}
It compiles fine, but when running I receive the following error message:
There was 1 failure:
1) initializationError(ScalaUnitTestExample)
java.lang.Exception: The @Rule 'testName' must be public.
at org.junit.internal.runners.rules.RuleFieldValidator.addError(RuleFieldValidator.java:90)
(...)
at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
FAILURES!!!
Tests run: 1, Failures: 1
The Java counterpart works as expected.
I've already tried the following (according to Using JUnit @Rule with ScalaTest (e.g. TemporaryFolder)):
val _testName = new TestName
@Rule def testName = _testName
but this did not really help. In this version the test cases run, but the {testName} results always {null}.
The default access rule in Scala is public, and therefore there is no public
keyword. On the other hand, the JUnit framework seems to consider it non-public.
Does anyone know how to overcome this problem? Another similar solution would also be fine! Thank you!
Upvotes: 1
Views: 1100
Reputation: 147
Use JUnit 4.12, I used @Jonas Anso's solution and it worked with that version, it did not work in 4.8 and 4.10. We have to set @Rule on a method, not on a field, seems that is ignored in 4.8 and 4.10. Also only getter is needed.
Upvotes: 0
Reputation: 473
Solution (with a light hack): put the method name logic into a base class written in Java. Java source (UnitTestBase.java
):
import org.junit.*;
import org.junit.rules.TestName;
public class UnitTestBase {
@Rule public TestName testName = new TestName();
@Before public void printTestCaseNameBefore() {
System.out.println("Start of test case " + testName.getMethodName());
}
@After public void printTestCaseNameAfter() {
System.out.println("End of test case " + testName.getMethodName());
}
}
Scala source (ScalaUnitTestExample.scala
):
import org.junit._
class ScalaUnitTestExample extends UnitTestBase {
@Test
def checkAddition() {
Assert.assertEquals(5, 2 + 3)
}
@Test
def checkMultiplication() {
Assert.assertEquals(6, 2 * 3)
}
}
Compile:
scalac -cp .;junit-4.9.jar UnitTestBase.java ScalaUnitTestExample.scala
Run:
scala -cp .;junit-4.9.jar org.junit.runner.JUnitCore ScalaUnitTestExample
Result:
JUnit version 4.9
.Start of test case checkMultiplication
End of test case checkMultiplication
.Start of test case checkAddition
End of test case checkAddition
Time: 0,005
OK (2 tests)
Upvotes: 0
Reputation: 2067
As you know scala default access rule is public, but scala does a trick, the field is private and it generates getters and setters, and that is the reason @Rule does not work in your code.
You can make it work using
import org.junit._
import org.junit.rules.TestName
class ScalaUnitTestExample {
var _testName: TestName = new TestName
@Rule
def testName = _testName
def testName_=(aTestName: TestName) {_testName = aTestName}
@Before def printTestCaseNameBefore() {
print("\nStart of test case " + testName.getMethodName)
}
@After def printTestCaseNameAfter() {
print("\nEnd of test case " + testName.getMethodName)
}
@Test
def checkAddition() {
Assert.assertEquals(5, 2 + 3)
}
@Test
def checkMultiplication() {
Assert.assertEquals(6, 2 * 3)
}
}
Anyway using ScalaTest or Specs2 would make your life easier.
Upvotes: 2