Dividere i metodi di una classe di test di jUnit in più file e creare un'applicazione multithreading

di il
4 risposte

Dividere i metodi di una classe di test di jUnit in più file e creare un'applicazione multithreading

Ciao a tutti,
Ho un problema non grave ma davvero scomodissimo che non riesco a risolvere.
Ho una classe con nome TestApplicazione.java dove eseguo N test di una data applicazione. Di questi N test una parte usano il database ed una parte no.
I metodi che operano sul database sono indipendenti ma usano le stesse tabelle del database. In sostanza ogni metodo, prima di partire, resetta in database.
Vorrei spezzettare il file in una decina di parti perché allo stato attuale, il contenuto è illeggibile e i tempi di calcolo alti.
Mi piacerebbe una cosa di questo tipo:
PRIMA:
TestApplicazione.java
DOPO:
TestApplicazione.java
TestApplicazioneParte1.java
TestApplicazioneParte2.java

TestApplicazioneParte5.java

Inoltre, vorrei creare due thread dove nel primo vengono eseguiti i test che si interfacciano con il database ed il secondo quelli che non usano il database.
E' possibile eseguire questo con jUnit, voi sareste in grado di dirmi come fare?
Grazie

4 Risposte

  • Re: Dividere i metodi di una classe di test di jUnit in più file e creare un'applicazione multithreading

    iBaffiPro ha scritto:


    Mi piacerebbe una cosa di questo tipo:
    PRIMA:
    TestApplicazione.java
    DOPO:
    TestApplicazione.java
    TestApplicazioneParte1.java
    TestApplicazioneParte2.java

    TestApplicazioneParte5.java
    Si può fare. L'approccio tipico è: se c'è una classe Xyz, si fa una XyzTest ma non è sbagliato farne di più di test per testare una stessa classe. Dipende ...

    iBaffiPro ha scritto:


    Inoltre, vorrei creare due thread dove nel primo vengono eseguiti i test che si interfacciano con il database ed il secondo quelli che non usano il database.
    In JUnit (5.x mi riferisco) normalmente per default i test sono tutti eseguiti sequenzialmente in un unico thread. C'è la possibilità di una parallelizzazione ma: a) è "sperimentale" per il momento, b) bisogna documentarsi: 2.19. Parallel Execution.

    Comunque, se il problema è che i test ci mettono "molto", la questione è capire perché. Gli unit-test NON devono metterci molto (altrimenti non si chiamerebbero "unit test"). Forse sono degli integration-test (?). Allora a) va verificato bene lo scenario, b) le classi andrebbero anche ben distinte dalle altre di test mettendo es. XyzIT (IT = Integration Test).
  • Re: Dividere i metodi di una classe di test di jUnit in più file e creare un'applicazione multithreading

    A grandi linee, ma non è sempre così, se ti può aiutare a capire, ho creato una classe di Test per ogni metodo del controller. Per farti capire meglio tu pensa alla classe TestApplicazione.java come una classe contenente tanti metodi di questo tipo:
    
    @SpringBootTest(classes = {GestioneUtentiApplication.class})
    public class PreTestApplicazione {
    
        @Autowired
        private UtenteRepository utenteRepository;
        @Autowired
        GestioneStrumenti gestioneStrumenti;
        @Autowired
        CalcolaVolume calcolaVolume;
        
        // ecc...
    
        @Test
        void contextLoads() {
        }
    
        public void caricaDatabasePerIlTest(){
            databasePerTest.restoreDatabaseTest();
        }
    
        @Test
        public void metodo1(){
            caricaDatabasePerIlTest();
            // ... ecc...
        }
        
        @Test
        public void metodo2(){
            caricaDatabasePerIlTest();
            // ... ecc...
        }
    
        // ... ecc...
    
        @Test
        public void metodoH(){
            // qui il database non viene neppure toccato...
        }
        
        // .. ecc...
        
        @Test
        public void metodoN-1(){
            caricaDatabasePerIlTest();
            // ... ecc...
        }
        
        @Test
        public void metodoN(){
            caricaDatabasePerIlTest();
            // ... ecc...
        }
    
    }
    
    Tutti i metodi che vedi, fatta eccezione per il metodo H (di metodo H c'è ne più di uno), si collegano al database, cancellano tutti i record presenti e caricano una serie di record sempre uguali (utenti, ruoli, ecc...). Quello che ti serve sapere è che il metodo2() può essere eseguito prima o dopo il metodo1() ma non contemporaneamente (non posso testare la modifica del nome di un utente con la fase di cancellazione di un utente, ecc...). Tra tutti questi metodi ce ne sono alcuni come il metodo H che possono essere eseguiti contemporaneamente al metodo1() e metodo2() perché indipendenti dal database.
    Quello che non voglio fare assolutamente è andare a modificare il codice di questi test.
    Altra cosa che non voglio assolutamente e creare X classi distinte e poi dall'IDE lanciarle una alla volta. Il mio obiettivo è avviare tutti i test da una classe principale.
    I problemi sono due:
    1) In PreTestApplicazione c'è troppo codice;
    2) Se riesco a parallelizzare ho una consistente riduzione dei tempi di calcolo.
  • Re: Dividere i metodi di una classe di test di jUnit in più file e creare un'applicazione multithreading

    iBaffiPro ha scritto:


    Tutti i metodi che vedi, fatta eccezione per il metodo H (di metodo H c'è ne più di uno), si collegano al database, cancellano tutti i record presenti e caricano una serie di record sempre uguali (utenti, ruoli, ecc...). Quello che ti serve sapere è che il metodo2() può essere eseguito prima o dopo il metodo1() ma non contemporaneamente (non posso testare la modifica del nome di un utente con la fase di cancellazione di un utente, ecc...). Tra tutti questi metodi ce ne sono alcuni come il metodo H che possono essere eseguiti contemporaneamente al metodo1() e metodo2() perché indipendenti dal database.
    Quello che hai fatto è chiaramente un integration-test (NON uno unit-test). Ed avendo quindi una base reale "persistente", i test NON devono interferire tra di loro. Quindi per ciascun caso di test ci deve essere una situazione ben nota e stabile sul DB (altrimenti i test vanno a pallino...).
    E vuol anche dire che devi avere un database specifico SOLO per questi test. Non puoi usare il database che usi per le tue prove "manuali" a livello di applicazione, né tanto meno quello di "produzione" (qualunque cosa tu abbia di ufficiale in produzione).

    iBaffiPro ha scritto:


    Quello che non voglio fare assolutamente è andare a modificare il codice di questi test.
    Altra cosa che non voglio assolutamente e creare X classi distinte e poi dall'IDE lanciarle una alla volta. Il mio obiettivo è avviare tutti i test da una classe principale.
    I test si possono avviare benissimo tutti insieme, sia da un IDE, sia dallo strumento di build in uso (Maven/Gradle). Con Maven banalmente: mvn test

    iBaffiPro ha scritto:


    1) In PreTestApplicazione c'è troppo codice;
    Non avendo visione chiara, non saprei cosa dire ora ...

    iBaffiPro ha scritto:


    2) Se riesco a parallelizzare ho una consistente riduzione dei tempi di calcolo.
    Ma la questione NON è arrivare alla parallelizzazione (che comunque come già detto è molto sperimentale e tutta da valutare). Ma capire bene perché i TUOI test ci mettono molto.
    Cosa fai esattamente per sistemare il db ad ogni test? E inoltre c'è anche da vedere (che ora non ricordo) come Spring Boot gestisce la Connection negli unit-test. Riusa la stessa connection? O crea una nuova connection ad ogni @Test? Utilizza un connection-pool? Insomma ... ora non ricordo, dovrei andare a leggere, magari qualcosa è ottimizzabile.

    E comunque essendo integration-test, è "normale" (detto in generale) che impieghino di più degli unit-test. Eventualmente si potrebbero "separare" dagli altri unit-test per poterli lanciare "a parte" e solo quando davvero si vuole.
  • Re: Dividere i metodi di una classe di test di jUnit in più file e creare un'applicazione multithreading

    Si ho un database specifico solo per i test. Il database che uso quando testo la webapp da browser che se ho capito bene tu chiami db per prove manuali coincide con quello per i test. Quando eseguo i test non eseguo prove da interfaccia grafica e viceversa, inoltre quando premo su 'run' e l'applicazione parte il database si azzera. Insomma, non sento l'esigenza di avere 2 database in fase di sviluppo. A volte ho fatto partire un test e sono andato a vedere come veniva editato l'html delle pagine. Avere 1 solo db in sviluppo può avere le sue convenienze. I test non li tocco più, se riuscissi vorrei solo 2 thread che girino in parallelo e stop. Non voglio parallelizzare i test, solo avere 2 thred in parallelo che è diverso da parallelizzare tutto. Per risistemare il database svuoto tutte le tabelle, in sostanza faccio in questo modo:
    
    DELETE FROM utenti CASCADE;
    DELETE FROM dimensioni CASCADE;
    ecc…
    
    Non so come verificare se jdbcTemplate usa la stessa connection oppure usa una connection-pool. Io ho creato una classe che svuota tutto e rimette utenti e ruoli in un istante. A volte riazzero tutto anche a metà test. Il fatto che ci voglia del tempo è normale, faccio molti test. Comunque quello che mi da maggiormente fastidio non è il tempo di esecuzione dei thread ma non poter dividere questo codice su più file. Al momento ho solo 2 file, uno lo chiamo TestApplicazione.java e l’altro lo chiamo PreTestApplicazione.java (lo so ho poca fantasia... ), quando finisco di progettare un integration-test per una data funzionalità della mia applicazione e su PreTestApplicazione.java funziona tutto senza problemi sposto tutti i metodi in TestApplicazione.java, facendo questo da molto tempo TestApplicazione.java è diventato lungo come la divina commedia e lo avvio solo prima di mangiare merenda o vado a dare da mangiare al mio cagnolone. Ho letto il discorso del 'mvn test' ma io voglio semplicemente premere su di un pulsante dell'IDE.
    Non ho parlato di db di produzione perché non ho neppure un server, sono lontano anni luce da avere un dominio, un server su cui installare tomcat e postgresql.
    Se possibile vorrei evitare di dividere il codice in TestApplicazioneParte1.java, TestApplicazioneParte2.java, TestApplicazioneParte3.java, ecc..., convertire tali classi in @Service, rimuovere l'annotazione @Test e poi da TestApplicazione.java lanciare il singolo test in questo modo:
        @Autowired
        TestApplicazioneParte1 testApplicazioneParte1;
        @Test
        public void test1(){
            testApplicazioneParte1.test1();
        }
    Mi sembra una soluzione un po' brutale, trovo anche strano che jUnit non abbia pensato a nulla di più ingenioso.
    Sempre grazie per il tuo tempo
Devi accedere o registrarti per scrivere nel forum
4 risposte