2012-11-01 12 views
11

Ho un interfaccia, ad es .:Riutilizzo di implementazioni di test in JUnit 4?

public interface Thing { 
    FrobResult frob(FrobInput); 
} 

E diverse implementazioni di tale interfaccia (ad esempio NormalThing, ImmutableThing, AsyncThing) che sto cercando di testare.

Molti dei miei metodi di test servono davvero a garantire che l'interfaccia sia implementata correttamente e quindi siano duplicati su ciascuna implementazione Thing. In JUnit 3 una soluzione comune a questo sarebbe creare una classe base (che si estende TestCase) che è quindi sottoclassata da ciascuna classe di implementazione. Ma questo è l'approccio corretto per JUnit 4?

Possibili alternative a (credo) ordine crescente di preferenza:

  1. cut'n'paste i metodi di prova duplicati. Non è affatto ASCIUTTO, ma credo sia meno preoccupante nei test che nel codice di produzione.

  2. Creare una classe astratta con i metodi @Test e sottoclasse per ogni classe di test di implementazione. (Comunemente visto con i test JUnit 3 - è ancora un buon modo per andare in JUnit 4?)

  3. Metti i metodi di test comuni in una classe helper e invocalo su ogni implementazione. (Composizione invece dell'eredità.)

Qual è la migliore pratica per fare # 3? Forse un test @RunWith(Parameterized.class) che è parametrizzato con ogni implementazione? O c'è un modo migliore per farlo?

+0

Sì, è l'approccio corretto per creare una classe base che è quindi sottoclassata da ogni classe di implementazione in JUnit4. – DaveFar

+0

@DaveBall: ti dispiacerebbe postare quella risposta? –

+1

# 3 sarebbe molto più bello, e sono d'accordo con il tuo commento qui sotto che sembra che questo dovrebbe essere possibile. –

risposta

5

Sì, è l'approccio corretto a creare una classe base che viene quindi sottoclassata da ogni classe di implementazione in JUnit4.

preferisco la classe di test di base per l'interfaccia di essere astratto, vale a dire il vostro "alternativo" 2, dal momento che ho fatto una buona esperienza nel mimicing gerarchia di ereditarietà dal codice di produzione per il codice di prova. Quindi, se avete l'interfaccia I e le implementazioni S1, S2 e S3, è rendere la classe di test astratta TestI e le classi di test TestS1, TestS2 e TestS3.

I test dovrebbero essere in conversazione, ad esempio indicare una storia. Scegliendo - come sempre - i nomi dei metodi con attenzione e usando solo la sottotipizzazione comportamentale pulita, l'ereditarietà non lo offusca.

+0

Anche questo è stato il mio primo pensiero, anche se sembra che ci debba essere un modo nuovo e brillante di eseguire mix-in di metodi di test, dal momento che sembra un caso comune. +1 ma attenderà che un altro intervieni prima di darti il ​​segno di spunta. –

1

Uso l'approccio n. 2 per i casi di test JUnit e TestNG. Questo è più conveniente e facile da mantenere. È anche semplice da raccogliere (dal momento che è nativo di OOD per avere una classe base che ha metodi comuni). Per me le classi di test unitarie non sono diverse dalle normali classi di progetto ... quindi applico considerazioni progettuali simili.

+1

È vero che le classi di test richiedono considerazioni progettuali, ma non direi che non sono diverse dalle normali classi di progetto. Ma in entrambi i casi, la mia preferenza è seguire * Java efficace * Articolo 16: Favorisci la composizione sull'ereditarietà. L'ereditarietà (che è in realtà la creazione di una relazione "è-a") è in genere un modo scadente per implementare il riutilizzo del codice. –

+0

Beh, tutto dipende ... normalmente uso la composizione e l'ereditarietà insieme. Alcune funzionalità di base che appartengono solo alla gerarchia che inserisco nella classe base e alcune funzionalità che possono essere riutilizzate al di fuori della mia gerarchia (cioè elementi libreria/componente), inserisco come composizione. Quindi dovresti usare l'approccio n. 2 e n. 3 insieme (beh, ho aggiunto qui la mia risposta) :) – user1697575