Jay Hacker
Jay Hacker

Reputation: 1915

How can I use JUnit ExpectedException in Scala?

I'd like to be able to use JUnit 4.7's ExpectedException @Rule in Scala. However, it doesn't seem to catch anything:

import org.junit._

class ExceptionsHappen {

  @Rule 
  def thrown = rules.ExpectedException.none

  @Test
  def badInt: Unit = {
    thrown.expect(classOf[NumberFormatException])
    Integer.parseInt("one")
  }
}

This still fails with a NumberFormatException.

Upvotes: 6

Views: 2110

Answers (6)

Ion Freeman
Ion Freeman

Reputation: 540

I'm still using JUnit 4, and found @Juh_'s comment instructive. This worked in Scala 2.11.0.

import org.junit.rules.ExpectedException
import org.junit.{Rule, Test}

import scala.reflect.{ClassTag, classTag}

class DeleteMe {

  object Thrower {
    def throwException[R <: Throwable: ClassTag](message: String): Unit = {
      throw classTag[R].runtimeClass.getConstructor(classOf[String]).newInstance(message).asInstanceOf[R]
    }
  }

  @Rule
  def exceptionRule:ExpectedException = ExpectedException.none()

  @Test(expected = classOf[Exception])
  def checkConversionExceptions = {
    val myMessage = "My Message"
    exceptionRule.expectMessage(myMessage)
    Thrower.throwException[Exception](myMessage)
    ()
  }
}

Upvotes: 0

lmm
lmm

Reputation: 17431

To make this work with JUnit 4.11 in Scala, you should meta-annotate your annotation so that the annotation is applied only to the (synthetic) getter method, not the underlying field:

import org.junit._
import scala.annotation.meta.getter

class ExceptionsHappen {

  @(Rule @getter)
  var thrown = rules.ExpectedException.none

  @Test
  def badInt: Unit = {
    thrown.expect(classOf[NumberFormatException])
    Integer.parseInt("one")
  }
}

Upvotes: 10

RobMcZag
RobMcZag

Reputation: 645

As a very newbie to Scala I am just using a very simple workaround: explicitly catch the exception and fail if your expected exception is not thrown.

Below is a sample skeleton:

try {
  *your code that should throw an exception*
  fail("Did not generate *the.Exception.you.expect*")
} catch {
  case t: *the.Exception.you.expect* => // do nothing, it's expected :)
}

Upvotes: 1

Matthew Farwell
Matthew Farwell

Reputation: 61695

EDIT: Following the release of JUnit 4.11, you can now annotate a method with @Rule.

You will use it like:

private TemporaryFolder folder = new TemporaryFolder();

@Rule
public TemporaryFolder getFolder() {
    return folder;
}

For earlier versions of JUnit, see the answer below.

--

No, you can't use this directly from Scala. The field needs to be public and non-static. From org.junit.Rule:

public @interface Rule: Annotates fields that contain rules. Such a field must be public, not static, and a subtype of TestRule.

You cannot declare a public fields in Scala. All fields are private, and made accessible by accessors. See the answer to this question.

As well as this, there is already an enhancement request for junit (still Open):

Extend rules to support @Rule public MethodRule someRule() { return new SomeRule(); }

The other option is that it non-public fields be allowed, but this has already been rejected: Allow @Rule annotation on non-public fields.

So your options are:

  1. clone junit, and implement the first suggestion, the method, and submit a pull request
  2. Extend the Scala class from a java class which implements the @Rule

-

public class ExpectedExceptionTest {
    @Rule
    public ExpectedException thrown = ExpectedException.none();
}

and then inheriting from that:

class ExceptionsHappen extends ExpectedExceptionTest {

  @Test
  def badInt: Unit = {
    thrown.expect(classOf[NumberFormatException])
    Integer.parseInt("one")
  }
}

which works correctly.

Upvotes: 8

rwitzel
rwitzel

Reputation: 1818

If Scala has something similar like static imports, then catch-exception is an alternative to JUnit 4.7's ExpectedException @Rule.

Upvotes: 0

Ido Tamir
Ido Tamir

Reputation: 3127

Without knowing JUnit rules, and without testing it, because I don't have an appropriate setup at hand, I go out on a limb and suggest turning thrown into a val. I guess its some member that is initialized with something and then it gets some state and then some other machinery checks the state against something. You are always creating new ones and keep forgetting the expectation.

Upvotes: 0

Related Questions