Reputation: 1915
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
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
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
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
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:
-
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
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
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