Sempre sui Generics

di il
33 risposte

Sempre sui Generics

Buongiorno .

Non abbandono il precedente esercizio sui Generics che con il prezioso aiuto di andbin sono riuscito a portare avanti e capire cose interessanti .
Per il momento lo lascio in sospeso.
Ne propongo un'altro molto simile che introduce in più il concetto di TestUnit.
Vorrei capire la differenza nell'usare il main oppure il TestUnit.
Capire realmente a cosa serve la TestUnit e perche' si usa.

Il codice e' composto da tre classi .
classe Persona , Coppia parametrizzata con T e CoppiaTest.
Sono tre classi di esempio di una slide in formato pdf.
Una volta che ho compilato il programma ed eseguito , logicamente in out non ottengo niente .
Mi compare soltanto una linea verde dove vengono riportati alcuni valori e nient'altro.
Mi chiedo percio' a cosa serve eseguire il test e cosa svolge questo comando : assertSame(p1,coppia.getPrimo());



import java.util.*;

class Persona {
private String nome;
public Persona(String nome) {
this.nome = nome;
}
public String getNome() {
return this.nome;
}
}


public class Coppia<T> {
private T primo;
private T secondo;
public Coppia(T primo, T secondo) {
this.primo = primo;
this.secondo = secondo;
}
public T getPrimo() {
return this.primo;
}
public T getSecondo() {
return this.secondo;
}
public void setPrimo(T primo) {
this.primo = primo;
}
public void setSecondo(T secondo) {
this.secondo = secondo;
}
}



import static org.junit.Assert.*;
import org.junit.Test;
public class CoppiaTest {
@Test
public void testDiCoppiaDiPersone() {
Coppia<Persona> coppia;
Persona p1 = new Persona("Stanlio");
Persona p2 = new Persona("Olio");
coppia = new Coppia<Persona>(p1, p2);
assertSame(p1,coppia.getPrimo());
assertSame(p2,coppia.getSecondo());


}
}

33 Risposte

  • Re: Sempre sui Generics

    FabioJ ha scritto:


    Vorrei capire la differenza nell'usare il main oppure il TestUnit.
    Mi compare soltanto una linea verde dove vengono riportati alcuni valori e nient'altro.
    Gli "unit test" sono test automatici che servono per verificare che una "unità" di codice, una classe/metodo tipicamente, si comporta come ci si aspetta. Forse è meglio se leggi qualcosa a riguardo ... https://it.wikipedia.org/wiki/Unit_testing


    Comunque il testDiCoppiaDiPersone effettua un test abbastanza basilare: che Coppia sia in grado di memorizzare quegli oggetti Persona e di fornirli correttamente al di fuori con i due getter. Il test si aspetta infatti che i due oggetti restituiti dai getter siano gli STESSI oggetti, cioè stesso reference (assertSame) passati inizialmente a Coppia.
  • Re: Sempre sui Generics

    Secondo te e' complicato eseguire i test ? Ci vuole pratica ?

    Per eseguire il TestJUnit devo scaricarmi qualcos'altro oppure basta utilizzare Eclipse ?

    Sto provando ad utilizzare ad utilizzare questo sito http://junit.org/junit4 pero' gli argomenti non sono facili da capire .
  • Re: Sempre sui Generics

    FabioJ ha scritto:


    Secondo te e' complicato eseguire i test ? Ci vuole pratica ?
    "eseguirli" no, non è affatto difficile. "scriverli" invece è più difficile a seconda degli scenari.

    FabioJ ha scritto:


    Per eseguire il TestJUnit devo scaricarmi qualcos'altro oppure basta utilizzare Eclipse ?
    Serve una libreria per unit testing: JUnit oppure TestNG (sono le due principali in ambito Java). E se vuoi eseguire i test facilmente anche FUORI da un IDE, sarebbe meglio sfruttare un sistema di build come Apache Maven o similare.

    FabioJ ha scritto:


    Sto provando ad utilizzare ad utilizzare questo sito http://junit.org/junit4 pero' gli argomenti non sono facili da capire .
    Credo ti servano più "basi", cerca articoli/guide/tutorial a riguardo.
  • Re: Sempre sui Generics

    Prima di avventurarmi nell'istallazione di software per eseguire i test e confondermi ulteriolmente , volevo farti leggere l'ultima parte del file pdf che mi viene messo a disposizione dal tutor di ingegneria del software e programmazione ad oggetti.
    in questo esercizio viene chiesto di utilizzare Eclipse

    L'esercizio conclusivo che mi viene chiesto di svolgere e' il seguente :

    Scrivere (con Eclipse) una classe di test Junit per la classe
    Persone (dal Quiz di preparazione alla prima verifica)

    • In particolare testare il metodo int contaOmonimiDi(String nome)
    • Scrivere il codice del metodo int contaOmonimiDi(String nome)
    • Eseguire la classe di test Junit (se il test fallisce, correggere il
    metodo sotto test e far girare nuovamente la classe di test)


    public class Persone {
    private String[] nomi;
    public Persone(int n) {
    this.nomi = new String[n];
    }
    public int contaOmonimiDi(String nome) {
    // metodo da scrivere
    }
    public void aggiungiNome(int indice, String nome){
    this.nomi[indice] = nome;
    }
    }
  • Re: Sempre sui Generics

    FabioJ ha scritto:


    Scrivere (con Eclipse) una classe di test Junit per la classe
    Persone (dal Quiz di preparazione alla prima verifica)

    • In particolare testare il metodo int contaOmonimiDi(String nome)
    • Scrivere il codice del metodo int contaOmonimiDi(String nome)
    • Eseguire la classe di test Junit (se il test fallisce, correggere il
    metodo sotto test e far girare nuovamente la classe di test)

    public class Persone {
    [ .... ]
    }
    Ok, la classe Persone rappresenta semplicemente un elenco di nomi di lunghezza fissa .. né più né meno.

    Vediamo di spiegarti come si dovrebbe affrontare il testing. Secondo la metodologia TDD (test-driven development) lo sviluppo dovrebbe avvenire così: PRIMA si scrivono gli unit-test e poi DOPO si scrivono le implementazioni che sono sottoposte a test.
    A prima vista sembrerebbe un controsenso, come si può testare qualcosa che non esiste ancora? Innanzitutto servono le specifiche sull'elemento da testare. E le abbiamo. Sappiamo che ci sarà un metodo contaOmonimiDi che riceve un String (nome) e restituisce un int (numero di omonimi). Questo è sufficiente, almeno a livello concettuale.

    Poi è chiaro che se vuoi scrivere una classe di test che "compili", la classe e il metodo sottoposti a test (Persone e contaOmonimiDi) chiaramente devono perlomeno già esistere, anche se incomplete. Se non ci fossero, la classe di test non ti compila proprio per niente!

    Molto probabilmente hai già idea di cosa vorrà dire "contare" gli omonimi dato un nome in input. Per il momento NON pensare alla implementazione concreta, NON preoccuparti di questo. Anzi, l'obiettivo iniziale dovrebbe essere quello di far fallire TUTTI i test. Quindi in contaOmonimiDi fai lanciare una bella eccezione:
    public int contaOmonimiDi(String nome) {
        throw new RuntimeException("non implementato");
    }
    In questo modo TUTTI i test falliranno di certo. Ripeto, non preoccuparti che ora c'è una implementazione "farlocca".

    Ora pensa ai casi di test. Quali sono? Ce ne sono diversi, tra cui anche dei casi "limite".

    a) Dato un oggetto Persone che contiene { "Mario", "Roberto", "Mario" } tu ti aspetti che contaOmonimiDi con "Mario" dia 2
    b) Dato un oggetto Persone che contiene { "Mario", "Roberto", "Mario" } tu ti aspetti che contaOmonimiDi con "Gianni" dia 0

    Ma si dovrebbero anche considerare casi "limite" in cui ci sono dei null. Cosa dovrebbe succedere se nell'array di Persone non sono state messe delle stringhe a certi indici? La tua implementazione NON dovrà fallire (es. con NullPointerException) ma ragionevolmente dare il conteggio corretto (anche se fosse es. 0).

    A questo punto crea un metodo di test. Sui NOMI dei metodi di test si è sempre discusso molto e ci sono diverse scuole di pensiero. Non c'è una convenzione unica e comune. A riguardo puoi leggere https://dzone.com/articles/7-popular-unit-test-naming

    Quindi in una classe PersoneTest metti:

    @Test
    public void verificaContaOmonimiDiConNomeDuplicato() { .... }

    @Test
    public void verificaContaOmonimiDiConNomeNonPresente() { .... }

    Purtroppo in italiano non vengono granché i nomi. In inglese verrebbero meglio (vedi il link sopra). Ma del nome non ti preoccupare "troppo" in questo momento. Prova a scrivere i test per i due casi a) b) descritti sopra.
  • Re: Sempre sui Generics

    Andbin .
    Al momento non rispondo perche' sono un po' impegnato .
    Appena ho un po' di tempo ci ragiono un po' su e provo a dare una risposta.
    Grazie per il tuo prezioso aiuto.
  • Re: Sempre sui Generics

    Provo a rispondere a questa domanda :

    @Test
    public void verificaContaOmonimiDiConNomeDuplicato() { .... }

    Secondo me potrei utilizzare Comparable perche' Coppia e' parametrizzata a Persona .
    Una volta che ho eseguito la comparazione incremento un contatore .
    Potrebbe andar bene questo ragionamento ?

    Oppure utilizzate questo metodo:

    boolean contains(Object element);
    ritorna true se la collezione contiene un elemento uguale a quello passato come
    parametro (l'uguaglianza è verificata dal metodo equals())
  • Re: Sempre sui Generics

    Ma stai parlando del codice iniziale, quello con la Persona/Coppia<T> ... oppure dell' "ultima parte", quella con la classe Persone ??
  • Re: Sempre sui Generics

    E' vero . Il metodo deve riguardare questa parte di codice.
    Percio' il Test degli omonimi lo devo fare sull'array di nomi ? o no ?


    public class Persone {
    private String[] nomi;
    public Persone(int n) {
    this.nomi = new String[n];
    }
    public int contaOmonimiDi(String nome) {
    // metodo da scrivere
    }
    public void aggiungiNome(int indice, String nome){
    this.nomi[indice] = nome;
    }
    }
  • Re: Sempre sui Generics

    FabioJ ha scritto:


    E' vero . Il metodo deve riguardare questa parte di codice.
    Percio' il Test degli omonimi lo devo fare sull'array di nomi ? o no ?
    Sì, dovrai testare contaOmonimiDi. Rileggi quanto dicevo prima. Se hai dubbi, vediamo.
  • Re: Sempre sui Generics

    Purtroppo dubbi ne ho . L'argomento TEST non mi e' molto chiaro . Teoricamente l'ho capito praticamente no.

    Credo che nel metodo dovro' dovranno messi degli assert oppure equals pero' sto tirando ad indovinare ,
  • Re: Sempre sui Generics

    FabioJ ha scritto:


    Purtroppo dubbi ne ho . L'argomento TEST non mi e' molto chiaro . Teoricamente l'ho capito praticamente no.

    Credo che nel metodo dovro' dovranno messi degli assert oppure equals pero' sto tirando ad indovinare ,
    Allora: come ho detto prima, NON preoccuparti ora della implementazione di contaOmonimiDi. Puoi metterci un throw di una eccezione (vedi prima) oppure un return di un valore totalmente fasullo, es. return 1234; Non ha importanza se contaOmonimiDi ora è "farlocco" e non corretto.
    La cosa sufficiente al momento è che il tuo test compili nei confronti di Persone e contaOmonimiDi.

    Ora prendiamo il primo caso che avevo detto: dato un oggetto Persone che contiene { "Mario", "Roberto", "Mario" } tu ti aspetti che contaOmonimiDi con "Mario" dia 2

    Nel metodo che avevo ipotizzato prima:

    @Test
    public void verificaContaOmonimiDiConNomeDuplicato() { .... }

    dovrai fare diverse cose. Innanzitutto creare un oggetto Persone (di 3 elementi). Aggiungerai poi i nomi con aggiungiNome. Infine invocherai il contaOmonimiDi passando "Mario". Il risultato che ci aspettiamo è 2 e lo dovrai testare con uno dei metodi della Assert di JUnit che è:

    assertEquals(long expected, long actual)

    (non ne esiste uno con int ... long va bene, per conversione implicita a long!)

    Questo perché se i due numeri, quello che ti aspetti e quello "attuale" fornito da contaOmonimiDi corrispondono, allora assertEquals non causa nulla e il test "passa". Altrimenti se non coincidono, allora assertEquals lancia un AssertionError e questo fa fallire il test.
  • Re: Sempre sui Generics

    Andbin , le tue indicazioni sono chiare . Vediamo di riuscire a metterle in pratica.

    @Test
    public void verificaContaOmonimiDiConNomeDuplicato() { .... }

    dovrai fare diverse cose. Innanzitutto creare un oggetto Persone (di 3 elementi). Aggiungerai poi i nomi con aggiungiNome. Infine invocherai il contaOmonimiDi passando "Mario". Il risultato che ci aspettiamo è 2 e lo dovrai testare con uno dei metodi della Assert di JUnit che è:


    public void verificaContaOmonimiDiConNomeDuplicato() {

    Persona per;

    Persona p1 = new Persona ( );
    Persona p2 = new Persona ( );
    Persona p3 = new Persona ( );



    .... }

    Il primo dubbio:
    Creare un oggetto Persona di tre elementi: Si scrive cosi ??
  • Re: Sempre sui Generics

    FabioJ ha scritto:


    public void verificaContaOmonimiDiConNomeDuplicato() {

    Persona per;

    Persona p1 = new Persona ( );
    Persona p2 = new Persona ( );
    Persona p3 = new Persona ( );
    No, guarda bene il codice di Persone che avevi scritto tu:
    public class Persone {
        private String[] nomi;
    
        public Persone(int n) {           // <---------------- DA USARE
            this.nomi = new String[n];
        }
    
        public int contaOmonimiDi(String nome) {           // <---------------- DA TESTARE
            // metodo da scrivere
        }
    
        public void aggiungiNome(int indice, String nome) {           // <---------------- DA USARE
            this.nomi[indice] = nome;
        }
    }
Devi accedere o registrarti per scrivere nel forum
33 risposte