Scala 预期异常片段

发布于 2024-12-08 14:22:44 字数 1089 浏览 0 评论 0原文

我正在尝试模拟常见测试框架(例如 JUnit 或 TestNG)的预期异常行为。

这是我到目前为止可以想到的(有效):

trait ExpectAsserts
{
  self : {
    def fail (message : String)
    def success (message : String)
  } =>

  def expect[T](exceptionClass : Class[T])(test : => Unit)
  {
    try
    {
      test
      fail("exception not thrown")
    }
    catch
    {
      case expected : T => success("got exception " + expected)
      case other : Exception => fail("expected "+ exceptionClass + " but " + other + " thrown instead.")
    }
  }
}

object Main extends ExpectAsserts
{
  def main (args : Array[String])
  {
    expect(classOf[ArithmeticException])
    {
      throw new IllegalArgumentException // this should print an error message.
    }
  }

  def fail (s : String)
  {
    System.err.println(s)
  }

  def success(s : String)
  {
    System.out.println(s)
  }
}

该代码片段有一个用于执行代码的 main 方法。我的问题是抛出的异常进入第一个模式匹配语句:

case expected : T

尽管我实际上是说异常必须是 T 类型,即 IllegalArgumentException

有什么想法吗?

I'm trying to simulate the expected exception behavior of common testing frameworks (e.g. JUnit or TestNG).

Here's what I could come up with so far (working):

trait ExpectAsserts
{
  self : {
    def fail (message : String)
    def success (message : String)
  } =>

  def expect[T](exceptionClass : Class[T])(test : => Unit)
  {
    try
    {
      test
      fail("exception not thrown")
    }
    catch
    {
      case expected : T => success("got exception " + expected)
      case other : Exception => fail("expected "+ exceptionClass + " but " + other + " thrown instead.")
    }
  }
}

object Main extends ExpectAsserts
{
  def main (args : Array[String])
  {
    expect(classOf[ArithmeticException])
    {
      throw new IllegalArgumentException // this should print an error message.
    }
  }

  def fail (s : String)
  {
    System.err.println(s)
  }

  def success(s : String)
  {
    System.out.println(s)
  }
}

The snippet has a main method that exercises the code. My problem is that the exception thrown enters in the first pattern matching statement:

case expected : T

Although I'm actually saying that the exception has to be of type T, which would be IllegalArgumentException.

Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

☆獨立☆ 2024-12-15 14:22:45

使用 -unchecked 进行编译,您将看到一条警告,指出由于类型擦除,类型测试 expected: T始终返回 true。

scala> def foo[T](a: Any) = a match { 
     |    case _: T => "always will match!"
     | }
<console>:22: warning: abstract type T in type pattern T is unchecked since it is eliminated by erasure
          case _: T => "always will match!"
                  ^
foo: [T](a: Any)java.lang.String

scala> foo[String](0)
res3: java.lang.String = always will match!

既然您已经传入了类,您可以使用 Class#isInstance 代替。在您的代码中,这看起来像:

case expected if clazz.isInstance(expected) => success("got exception " + expected)

在一个独立的示例中。这里我们隐式地传递了一个 Manifest[T] ,这是一种让编译器传递额外参数来获取类型擦除丢弃的信息的方法:

scala> def foo[T: ClassManifest](a: Any) = manifest[T].erasure.isInstance(a)
foo: [T](a: Any)(implicit evidence$1: Manifest[T])Boolean

scala> foo[String](new {})  // compiler passes Manifest[String] here
res4: Boolean = false

scala> foo[String]("")
res5: Boolean = true

进一步阅读:

Compile with -unchecked and you'll see a warning that the type test expected: T will always return true, thanks to type erasure.

scala> def foo[T](a: Any) = a match { 
     |    case _: T => "always will match!"
     | }
<console>:22: warning: abstract type T in type pattern T is unchecked since it is eliminated by erasure
          case _: T => "always will match!"
                  ^
foo: [T](a: Any)java.lang.String

scala> foo[String](0)
res3: java.lang.String = always will match!

Seeing as you have the class passed in you can use Class#isInstance instead. In your code, that would look like:

case expected if clazz.isInstance(expected) => success("got exception " + expected)

In a self contained example. Here we pass a Manifest[T] implicitly, which is a way to get the compiler to pass an extra parameter to obtain the information that type erasure threw away:

scala> def foo[T: ClassManifest](a: Any) = manifest[T].erasure.isInstance(a)
foo: [T](a: Any)(implicit evidence$1: Manifest[T])Boolean

scala> foo[String](new {})  // compiler passes Manifest[String] here
res4: Boolean = false

scala> foo[String]("")
res5: Boolean = true

Further reading:

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文