Visualizzazione dei risultati da 1 a 5 su 5
  1. #1

    jUnit (@Before e @Test): cosa fanno di preciso?

    Non capisco esattamente l'utilità del secondo pezzo di codice (@Before e @Test). Su Eclipse leggo Errori 0 quindi dovrebbe essere tutto a posto ma non capisco che tipo di test fa.
    Cod 1
    codice:
    package lab1b;
    public class Customer {
        private String name;
        private String address;
        private double amountInvoiced;
        void SetName(String x) {
            this.name=x;
        }
        void SetAddress(String y) {
            this.address=y;
        }
        void SetAmountInvoiced(double z) {
            this.amountInvoiced=z;
        }
        String GetName() {
            //posso anche scrivere 'return name;'
            return this.name;
        }
        String GetAddress() {
            return this.address;
        }
        double GetAmountInvoiced() {
            return this.amountInvoiced;
        }
        /* (non-Javadoc)
         * @see java.lang.Object#hashCode()
         */
        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((address == null) ? 0 : address.hashCode());
            long temp;
            temp = Double.doubleToLongBits(amountInvoiced);
            result = prime * result + (int) (temp ^ (temp >>> 32));
            result = prime * result + ((name == null) ? 0 : name.hashCode());
            return result;
        }
        /* (non-Javadoc)
         * @see java.lang.Object#equals(java.lang.Object)
         */
        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null) {
                return false;
            }
            if (!(obj instanceof Customer)) {
                return false;
            }
            Customer other = (Customer) obj;
            if (address == null) {
                if (other.address != null) {
                    return false;
                }
            } else if (!address.equals(other.address)) {
                return false;
            }
            if (Double.doubleToLongBits(amountInvoiced) != Double.doubleToLongBits(other.amountInvoiced)) {
                return false;
            }
            if (name == null) {
                if (other.name != null) {
                    return false;
                }
            } else if (!name.equals(other.name)) {
                return false;
            }
            return true;
        }
    }
    Cod 2
    codice:
    package lab1b;
    
    import static org.junit.Assert.assertTrue;
    
    import org.junit.Before;
    import org.junit.Test;
    
    public class CustomerTest {
        private Customer c1, c2;
        
        @Before
        public void init() {
            c1=new Customer();
            c2=new Customer();
        }
        
        @Test
        public void testEqualsOk() {
            assertTrue(c1.equals(c2));
        }
    }
    In pratica, se ho capito bene, il secondo codice verifica che il metodo equals() riscritto con @Override al passaggio precedente funzioni alla perfezione e non contenga errori ma non capisco quali test esegua?
    Se scrivo:
    codice:
        @Override
        public boolean equals(Object obj) {
            
            return true;
        }
    i test passano tranquillamente dunque questo codice a che serve?
    codice:
    package lab1b;
    
    import static org.junit.Assert.assertTrue;
    
    import org.junit.Before;
    import org.junit.Test;
    
    public class CustomerTest {
        private Customer c1, c2;
        
        @Before
        public void init() {
            c1=new Customer();
            c2=new Customer();
        }
        
        @Test
        public void testEqualsOk() {
            assertTrue(c1.equals(c2));
        }
    }
    Perché è così importante!?! jUnit non dovrebbe prendere tutti i possibili valori dei singoli oggetti e testare che l'equals() di @Override funzioni esattamente come l'equals() originale?
    jUnit non dovrebbe fare qualcosa di più raffinato di quello che vi scrivo qui sotto?!?!
    codice:
    package lab1b;
    public class TestSemplice {
        public static void main( String[] args ) {
            Customer A = new Customer();
            A.SetName("Marco");
            A.SetAddress("Rossi");
            A.SetAmountInvoiced(12.695);
            System.out.println(A.GetName());
            System.out.println(A.GetAddress());
            System.out.println(A.GetAmountInvoiced());
            Customer B = new Customer();
            B.SetName("Marco");
            B.SetAddress("Rossi");
            B.SetAmountInvoiced(12.695);
            System.out.println(B.GetName());
            System.out.println(B.GetAddress());
            System.out.println(B.GetAmountInvoiced());
            //Senza @Override i due oggetti sono diversi
            System.out.println(A.equals(B));
            System.out.println("%%% TEST 1 %%%");
            if(A.equals(B) && A.hashCode()==B.hashCode()) {
                System.out.println("Gli oggetti confrontati con equals() e hashCode() modificati con @Override coincidono.");
            } else {
                System.out.println("Gli oggetti confrontati sono differenti.");
            }
            //hash() genera un codice a partire da una serie di oggetti
            //Se i 3 oggetti che compongono le 2 classi sono rispettivamente identici i codici hash coincidono
            System.out.println(A.hashCode());
            System.out.println(B.hashCode());
            //Altro esempio
            Customer C = new Customer();
            Customer D = null;
            System.out.println("%%% TEST 2 %%%");
            if(C.equals(D) && C.hashCode()==D.hashCode()) {
                System.out.println("Gli oggetti confrontati con equals() e hashCode() modificati con @Override coincidono.");
            } else {
                System.out.println("Gli oggetti confrontati sono differenti.");
            }
        }
    }
    ciao
    Più pratica in futuro...

  2. #2
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,254
    Quote Originariamente inviata da giannino1995 Visualizza il messaggio
    Non capisco esattamente l'utilità del secondo pezzo di codice (@Before e @Test).
    In JUnit l'annotazione @Test denota un metodo di "test" che JUnit esegue. L'annotazione @Before invece denota un metodo che viene sempre eseguito prima di ciascun metodo di test.
    E devi tenere presente che per ciascuna esecuzione di un metodo di test, JUnit crea una nuova istanza della classe di test.

    Quote Originariamente inviata da giannino1995 Visualizza il messaggio
    In pratica, se ho capito bene, il secondo codice verifica che il metodo equals() riscritto con @Override al passaggio precedente funzioni alla perfezione e non contenga errori ma non capisco quali test esegua?
    Sì, l'obiettivo di testEqualsOk sarebbe di testare che equals funzioni correttamente ma .... in realtà è poco "robusto". Non tanto il testEqualsOk in sé (che è corretto) ma il "setup" dei due oggetti. Il init() va sì a creare 2 Customer distinti ma contengono solo valori di default (null e 0.0) e questo è poco utile.

    Quindi bisognerebbe:
    a) impostare dati fittizzi negli oggetti e oltretutto fare in modo che per gli oggetti contenuti siano proprio distinti. Quindi per c1 che abbia una stringa es. "aCustomer" e c2 abbia un ALTRO oggetto String che sia sempre "aCustomer".
    b) fare più casi di test, compreso anche il caso contrario dove si verifica che due oggetti siano diversi.

    Altrimenti il CustomerTest non servirebbe a un piffero.

    Quote Originariamente inviata da giannino1995 Visualizza il messaggio
    Se scrivo:
    codice:
        @Override
        public boolean equals(Object obj) {
            
            return true;
        }
    i test passano tranquillamente dunque questo codice a che serve?
    Appunto ... servono PIÙ casi di test (e con dati più appropriati).


    P.S. i setter/getter non sono "convenzionali" perché li hai messi con la iniziale maiuscola.
    Ultima modifica di andbin; 18-06-2018 a 14:17
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    Java Versions Cheat Sheet

  3. #3
    Ok, grazie per il supporto, ma se devo creare io i test con jUnit allora dove sta il vantaggio? Cioè, se devo scrivere questo, e cercare io i bug:
    codice:
    package lab1b;
    
    import static org.junit.Assert.assertTrue;
    
    import org.junit.Before;
    import org.junit.Test;
    
    public class CustomerTest {
        private Customer c1, c2, A, B, C, D, E, F;
        
        @Before
        public void init() {
            c1=new Customer();
            c2=new Customer();
            A = new Customer();
            A.SetName("Marco");
            A.SetAddress("Rossi");
            A.SetAmountInvoiced(12.695);
            B = new Customer();
            B.SetName("Marco");
            B.SetAddress("Rossi");
            B.SetAmountInvoiced(12.695);
            C = new Customer();
            // Trasformo l'oggetto Customer D in null.
            D = null;
            E = new Customer();
            E.SetName("Marco");
            E.SetAddress("Rossi");
            F = new Customer();
            F.SetName("Marco");
            F.SetAddress("Rossi");
        }
        
        @Test
        public void testEqualsOk() {
            assertTrue(c1.equals(c2));
            assertTrue(A.equals(A));
            assertTrue(B.equals(B));
            assertTrue(C.equals(C));
            assertTrue(A.equals(B));
            assertTrue(!C.equals(D));
            assertTrue(B.equals(A));
            assertTrue(E.equals(F));
            //Questi test danno errore perché D è null e non un oggetto Customer:
            //assertTrue(!D.equals(D));
            //assertTrue(!D.equals(C));
        }
    }
    che vantaggio ho ad usare jUnit? Perché non usare un semplice ciclo if? Non riesco a vedere l'utilità e la straordinarietà di queste annotazioni aggiuntive del framework.
    Più pratica in futuro...

  4. #4
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,254
    Quote Originariamente inviata da giannino1995 Visualizza il messaggio
    codice:
        @Test
        public void testEqualsOk() {
            assertTrue(c1.equals(c2));
            assertTrue(A.equals(A));
            assertTrue(B.equals(B));
            assertTrue(C.equals(C));
            assertTrue(A.equals(B));
            assertTrue(!C.equals(D));
            assertTrue(B.equals(A));
            assertTrue(E.equals(F));
            //Questi test danno errore perché D è null e non un oggetto Customer:
            //assertTrue(!D.equals(D));
            //assertTrue(!D.equals(C));
        }
    }
    Un metodo come questo NON va affatto bene. E non solo per i nomi delle variabili (oltretutto maiuscoli!) che dicono abbastanza poco.
    Ma soprattutto per un aspetto molto più importante. Il tuo testEqualsOk fa "troppe" cose. Se questo metodo fallisce in JUnit tu NON riesci a capire bene subito QUALE dei sotto-casi è fallito.

    1 caso di test <--> 1 metodo @Test
    punto


    Riguardo il "quale è il vantaggio di JUnit", innanzitutto bisogna anche vedere in che ottica "vedi" lo sviluppo dei test. Bisogna vedere in generale se si intende affrontare l'approccio TDD (Test Driven Development) in cui PRIMA scrivi i test e POI scrivi la implementazione del codice da testare. E inoltre se sei la stessa persona che scrive il codice e i test (come presumo sia il tuo caso) perché ovviamente in questo caso si è un po' "influenzati" da come si pensa/scrive la implementazione.
    Ma queste sono questioni un po' più filosofiche ....
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    Java Versions Cheat Sheet

  5. #5
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,254
    @giannino1995: giusto per informazione (e per il "futuro"), ti mostro come si può fare meglio.

    codice:
    public class CustomerTest {
        private static final String NAME_A = "Name A";
        private static final String NAME_B = "Name B";
        private static final String ADDRESS_A = "Address A";
        private static final String ADDRESS_B = "Address B";
        private static final double AMOUNT_A = 1234.5;
        private static final double AMOUNT_B = 5678.5;
    
        @Test
        public void equalsWithDifferentNameShouldGiveNotEqual() {
            Customer c1 = createCustomer(NAME_A, ADDRESS_A, AMOUNT_A);
            Customer c2 = createCustomer(NAME_B, ADDRESS_A, AMOUNT_A);
            assertFalse("The two customers should be NOT equal for different names", c1.equals(c2));
        }
    
        @Test
        public void equalsWithNullParameterShouldGiveNotEqual() {
            Customer c1 = createCustomer(NAME_A, ADDRESS_A, AMOUNT_A);
            assertFalse("The customer should be NOT equal to null", c1.equals(null));
        }
    
        // ... altri test ...
    
        private static Customer createCustomer(String name, String address, double amountInvoiced) {
            Customer c = new Customer();
            c.setName(new String(name));
            c.setAddress(new String(address));
            c.setAmountInvoiced(amountInvoiced);
            return c;
        }
    }

    Nota un po' di cose:

    1) Ho usato un metodo statico di "utilità" per creare il Customer. Nota che ho usato il costruttore String(String) per le stringhe. Questo costruttore è normalmente (nella programmazione comune) una delle cose più inutili del framework, siccome le stringhe sono immutabili e quindi condivisibili. Ma in questo caso molto specifico è utile. Serve per avere stringhe distinte (due Customer che hanno stesso nome ma come oggetti String distinti).

    2) Nota i nomi dei metodi. Non c'è purtroppo un accordo standard sulla denominazione dei metodi di test. Se cerchi in rete trovi idee e pareri discordanti e ben differenti. Esistono diverse convenzioni note. La forma che ho usato io è una scelta mia, memore di ciò che ho già letto e fatto in passato. I nomi sono effettivamente lunghi ma NON importa, l'importante è che siano esplicativi di COSA sta testando il metodo.

    3) Guarda il primo test, ho fatto variare solo il nome, NON il resto. Variare il name è un caso. Variare l'address è un ALTRO caso di test.
    Se mischi i casi nello stesso metodo @Test: a) è meno facile dare il nome al metodo, b) se fallisce è meno facile capire QUALE caso è fallito.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    Java Versions Cheat Sheet

  6. #6
    grazie di tutto andbin
    Più pratica in futuro...

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.