2011-10-23 13 views
6

Ho iniziato ad imparare Scala ieri, quindi sono abbastanza nuovo. Una cosa che mi piace fare quando apprendo una nuova lingua è cercare di creare una lib di micro-TDD.Scala - Come si esegue un metodo "assertThrows"?

Questo è quello che ho ottenuto finora:

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

Il codice per assert funziona bene, ma sto avendo problemi con due assertThrows.

  • Sembra che non sia possibile utilizzare E sull'ultima riga. Non importa quello che faccio, ottengo un class type expected but E found error.
  • Se rimuovo E dall'ultima riga (sostituendolo con throw new AssertionError("error expected"), per esempio) ottengo questo: warning: abstract type E in type pattern is unchecked since it is eliminated by erasure

Penso che i due problemi che sto avendo sono correlati con il modo in Scala (e, probabilmente, java) si occupa di tipi astratti e di come sono fatti.

Come posso risolvere il mio assertThrows?

Punti bonus: è il modo in cui sto specificando un "tipo di blocco" (f: => Unit) corretto?

+1

Una domanda che non avevo molto tempo fa potrebbe essere di aiuto: http://stackoverflow.com/questions/7699709/scala-expected-exception-snippet –

risposta

8

La macchina virtuale Java implementa i generici tramite la cancellazione dei tipi, quindi all'interno del corpo del metodo la JVM non sa nulla sul tipo E, quindi questo metodo AssertThrows non può funzionare nel modo desiderato. È necessario passare implicitamente un manifesto per la classe di eccezione, in questo modo:

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

quindi è possibile utilizzare nel corpo per catturare l'eccezione o ottenere il nome della classe in questo modo:

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

Grazie per the Spring framework's AssertThrows class per avermi mostrato come farlo.

+0

Grazie per la risposta. Puoi includere un esempio di utilizzo? Non sono in grado di farlo funzionare. – kikito

+0

Non importa, l'ho fatto funzionare (ho aggiunto una risposta). Sto modificando un piccolo refuso nella risposta e contrassegnandolo come corretto. – kikito

0

ho avuto questa cosa, grazie al lavoro per la risposta di 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! 

Grazie mille!

+0

Davvero fantastico !! –

Problemi correlati