Csaba Faragó
Csaba Faragó

Reputation: 473

Logging unit test name in Scala

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

Answers (3)

user10439725
user10439725

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

Csaba Faragó
Csaba Faragó

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

Jonas Anso
Jonas Anso

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

enter image description here

Anyway using ScalaTest or Specs2 would make your life easier.

Upvotes: 2

Related Questions