Scala ожидается фрагмент кода - PullRequest
0 голосов
/ 09 октября 2011

Я пытаюсь смоделировать ожидаемое поведение исключительной ситуации в обычных средах тестирования (например, 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.

Есть идеи?

1 Ответ

5 голосов
/ 09 октября 2011

Скомпилируйте с -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

Дополнительная информация:

...