Java 8 rende tutto molto più semplice e Kotlin / Scala lo sono doppiamente.
Possiamo scrivere una piccola classe di utilità
class MyAssertions{
public static void assertDoesNotThrow(FailingRunnable action){
try{
action.run()
}
catch(Exception ex){
throw new Error("expected action not to throw, but it did!", ex)
}
}
}
@FunctionalInterface interface FailingRunnable { void run() throws Exception }
e quindi il tuo codice diventa semplicemente:
@Test
public void foo(){
MyAssertions.assertDoesNotThrow(() -> {
//execute code that you expect not to throw Exceptions.
}
}
Se non hai accesso a Java-8, utilizzerei una funzione java dolorosamente vecchia: blocchi di codice aribitrary e un semplice commento
//setup
Component component = new Component();
//act
configure(component);
//assert
/*assert does not throw*/{
component.doSomething();
}
E infine, con Kotlin, una lingua di cui mi sono innamorato di recente:
fun (() -> Any?).shouldNotThrow()
= try { invoke() } catch (ex : Exception){ throw Error("expected not to throw!", ex) }
@Test fun `when foo happens should not throw`(){
//...
{ /*code that shouldn't throw*/ }.shouldNotThrow()
}
Sebbene ci sia un sacco di spazio per giocherellare con il modo in cui vuoi esprimere questo, sono sempre stato un fan delle asserzioni fluide .
per quanto riguarda
Ti stai avvicinando nel modo sbagliato. Metti alla prova la tua funzionalità: se viene generata un'eccezione, il test fallirà automaticamente. Se non viene generata alcuna eccezione, i test diventeranno tutti verdi.
Ciò è corretto in linea di principio, ma in conclusione errato.
Java consente eccezioni per il flusso di controllo. Ciò viene eseguito dal runtime JRE stesso nelle API come Double.parseDouble
tramite a NumberFormatException
e Paths.get
tramite a InvalidPathException
.
Dato che hai scritto un componente che convalida le stringhe numeriche per Double.ParseDouble
, magari usando un Regex, forse un parser scritto a mano o forse qualcosa che incorpora alcune altre regole di dominio che limita l'intervallo di un doppio a qualcosa di specifico, il modo migliore per testarlo componente? Penso che un ovvio test sarebbe quello di affermare che, quando viene analizzata la stringa risultante, non viene generata alcuna eccezione. Vorrei scrivere quel test utilizzando il sopra assertDoesNotThrow
o il /*comment*/{code}
blocco. Qualcosa di simile a
@Test public void given_validator_accepts_string_result_should_be_interpretable_by_doubleParseDouble(){
//setup
String input = "12.34E+26" //a string double with domain significance
//act
boolean isValid = component.validate(input)
//assert -- using the library 'assertJ', my personal favourite
assertThat(isValid).describedAs(input + " was considered valid by component").isTrue();
assertDoesNotThrow(() -> Double.parseDouble(input));
}
Vorrei anche incoraggiarvi a parametrizzare questo test input
sull'uso Theories
o in Parameterized
modo da poter riutilizzare più facilmente questo test per altri input. In alternativa, se vuoi diventare esotico, potresti scegliere uno strumento di generazione di test (e questo ). TestNG ha un supporto migliore per i test con parametri.
Ciò che trovo particolarmente spiacevole è la raccomandazione di utilizzare @Test(expectedException=IllegalArgumentException.class)
, questa eccezione è pericolosamente ampia . Se il tuo codice cambia in modo tale che il componente sotto il costruttore del test ha if(constructorArgument <= 0) throw IllegalArgumentException()
, e il tuo test ha fornito 0 per quell'argomento perché era conveniente - e questo è molto comune, perché la buona generazione di dati di test è un problema sorprendentemente difficile -, quindi il tuo test sarà una barra verde anche se non verifica nulla. Tale test è peggio che inutile.