简体   繁体   English

如何在 Scala 中使用 JUnit ExpectedException?

[英]How can I use JUnit ExpectedException in Scala?

I'd like to be able to use JUnit 4.7's ExpectedException @Rule in Scala.我希望能够在 Scala 中使用 JUnit 4.7 的ExpectedException @Rule 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 .这仍然失败,并出现NumberFormatException

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:为了在 Scala 中使用 JUnit 4.11,您应该对注释进行元注释,以便注释仅应用于(合成)getter 方法,而不是基础字段:

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

EDIT: Following the release of JUnit 4.11, you can now annotate a method with @Rule .编辑:在 JUnit 4.11 发布之后,您现在可以使用@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.对于早期版本的 JUnit,请参阅下面的答案。

-- ——

No, you can't use this directly from Scala.不,您不能直接从 Scala 使用它。 The field needs to be public and non-static.该字段需要是公共的和非静态的。 From org.junit.Rule :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.您不能在 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):除此之外,已经有一个junit的增强请求(仍然开放):

Extend rules to support @Rule public MethodRule someRule() { return new SomeRule();扩展规则以支持@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 .另一种选择是允许非公共字段,但这已经被拒绝:允许在非公共字段上使用 @Rule 注释

So your options are:所以你的选择是:

  1. clone junit, and implement the first suggestion, the method, and submit a pull request克隆junit,并实现第一个建议,方法,并提交拉取请求
  2. Extend the Scala class from a java class which implements the @Rule从实现 @Rule 的 java 类扩展 Scala 类

- ——

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.哪个工作正常。

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.作为 Scala 的新手,我只是使用了一个非常简单的解决方法:如果没有抛出预期的异常,则显式捕获异常并失败。

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

如果 Scala 有类似静态导入的东西,那么catch-exception是 JUnit 4.7 的 ExpectedException @Rule 的替代品。

I'm still using JUnit 4, and found @Juh_'s comment instructive.我仍在使用 JUnit 4,发现 @Juh_ 的评论很有启发性。 This worked in Scala 2.11.0.这在 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)
    ()
  }
}

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.在不了解 JUnit 规则的情况下,也没有对其进行测试,因为我手头没有合适的设置,所以我冒昧地建议把它扔进一个 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.你总是在创造新的,并不断忘记期望。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM