2011-10-23 20 views
6

Empecé a aprender Scala ayer, así que soy bastante nuevo. Una cosa que me gusta hacer cuando estoy aprendiendo un nuevo idioma es tratar de crear una lib de micro-TDD.Scala: ¿cómo hago un método "assertThrows"?

Esto es lo que tengo hasta ahora:

def assert(condition: Boolean, message: String) { 
    if(!condition){ throw new AssertionError(message) } 
} 

def assertThrows[E](f: => Unit) { 
    try { 
    f 
    } catch { 
    case e: E => { return } 
    case _: Exception => { } 
    } 
    throw new AssertionError("Expected error of type " + classOf[E]) 
} 

El código para assert funciona muy bien, pero estoy teniendo problemas con dos assertThrows.

  • Parece que no puedo usar E en la última línea. No importa lo que haga, obtengo un class type expected but E found error.
  • Si quito E de la última línea (sustituyéndolo por throw new AssertionError("error expected"), por ejemplo) me sale esto: warning: abstract type E in type pattern is unchecked since it is eliminated by erasure

Creo que los dos problemas que tengo están relacionados con la forma en Scala (y, probablemente, java) trata sobre tipos abstractos y cómo se hacen.

¿Cómo puedo solucionar mi assertThrows?

Puntos de bonificación: es la forma en que estoy especificando un "tipo de bloque" (f: => Unit) ¿correcto?

+1

Una pregunta que no hace mucho tiempo podría ser de ayuda: http://stackoverflow.com/questions/7699709/scala-expected-snippet –

Respuesta

8

La máquina virtual Java implementa genéricos mediante el borrado de tipos, por lo que dentro del cuerpo del método, la JVM no sabe realmente qué tipo de letra es E, por lo que este método no puede funcionar de la forma que desee. Tiene que pasar implícita de un manifiesto para su clase de excepción, así:

def assertThrows[E](f: => Unit)(implicit eType:ClassManifest[E]) { 

A continuación, puede usarlo en el cuerpo para detectar la excepción u obtener el nombre de la clase, así:

try { 
    f 
    } catch { 
    case e: Exception => 
     if (eType.erasure.isAssignableFrom(e.getClass)) 
     return; 
    } 
    throw new AssertionError("Expected error of type " + eType.erasure.getName) 
} 

Gracias a the Spring framework's AssertThrows class por mostrarme cómo hacer esto.

+0

Gracias por su respuesta. ¿Puedes incluir un ejemplo de uso? No puedo hacerlo funcionar. – kikito

+0

No importa, lo tengo funcionando (agregué una respuesta). Estoy editando un pequeño error ortográfico en su respuesta y marcándolo como correcto. – kikito

0

Tengo esta cosa de trabajo gracias a la respuesta de Ken:

class AssertException(msg: String) extends Exception(msg: String) 

def assertThrows[E](f: => Unit)(implicit eType:ClassManifest[E]) { 
    try{ 
    f 
    } catch { 
    case e: Exception => 
    if(eType.erasure.isAssignableFrom(e.getClass)) { return } 
    } 
    throw new AssertException("Expected error of type " + eType.erasure.getName) 
} 

/* examples of usage */ 

assertThrows[NullPointerException]{ throw new NullPointerException() } // ok 
assertThrows[AssertException] { assertThrows[Exception]{ } } // ok! 

Muchas gracias!

+0

¡¡Realmente increíble !! –

Cuestiones relacionadas