Exercices test JUnit

Le but de ces exercices est de réaliser le test d'une application complète dont le but est de présenter les résultats des match de pro A

Le match est vu comme le bilan des actions de chaque joueur. Les données sont organisées de la facon suivante :

Diagramme de classe du projet

L'application permet de :

  • Récupérer les résultats et les statistiques des derniers matchs joués via le web service de la LNB
  • Calculer un certain nombre de statistiques sur les joueurs et les match
  • Afficher les statistiques des match dans une ihm développée en Swing

Les sources de l'application dont disponnibles ici : projet basket

1. Test des services sans DAO

Un service fr.julien.formation.basket.services.CalculStatistiquesService permet de calculer :

  • Le nombre de points d'un joueur au cours d'un match
  • L'évaluation d'un joueur : points + rebonds + passes décisives + interceptions + contres + tirs réussis - tirs ratés - ballons perdus

Le but de l'exercice et de :

  1. Déterminer quelles méthodes et quelles classes doivent être testées pour le service et les classes métier utilisées
  2. Réaliser les tests et corriger les erreurs éventuelles détectées
  3. Se poser des questions sur la qualité du jeu de tests

Les classes à tester sont :

  • CalculStatistiquesService : de facon évidente
  • Joueur : pour la méthode equals()
  • Equipe : pour la méthode equals()


public class CalculStatistiqueServiceTest {

    @Test
    public void testerCalculScore() {
        Joueur kyle = new Joueur("MCALARNEY", "Kyle", new Equipe("OLB"));
        BilanJoueur bilan = new BilanJoueur(kyle, 1, 1, 7, 6, 7, 2, 3, 5, 2, 1, 1, 2);
        Assert.assertEquals(19, CalculStatistiquesService.getInstance().calculerScore(bilan));
        Assert.assertEquals(20, CalculStatistiquesService.getInstance().calculerEvaluation(bilan));
    }
}

public class EquipeTest {

    @Test
    public void testerEquals() {
        Equipe e1 = new Equipe("Orléans");
        Equipe e2 = new Equipe("Orléans");
        Equipe e3 = new Equipe("ASVEL");
        Assert.assertEquals(true, e1.equals(e2));
        Assert.assertEquals(false, e1.equals(e3));
    }
}

public class JoueurTest {

    @Test
    public void testerEquals() {
        Joueur kyle = new Joueur("MCALARNEY", "Kyle", new Equipe("OLB"));
        Joueur kyle2 = new Joueur("MCALARNEY", "Kyle", new Equipe("OLB"));
        Joueur kyle3 = new Joueur("MCALARNEY", "Kyle", new Equipe("Monaco"));
        Joueur kyle4 = new Joueur("MCALARNEY", "Autre", new Equipe("OLB"));
        Joueur cellus = new Joueur("SOMMERVILLE", "Marcellus", new Equipe("OLB"));
        Joueur cellus2 = new Joueur("SOMMERVILLE", "Kyle", new Equipe("OLB"));
        Assert.assertEquals(true, kyle.equals(kyle2));
        Assert.assertEquals(false, kyle.equals(kyle3));
        Assert.assertEquals(false, kyle.equals(kyle4));
        Assert.assertEquals(false, kyle.equals(cellus));
        Assert.assertEquals(false, kyle.equals(cellus2));
    }
}

Le jeu de test est de qualité si :

  • La suppression d'un Assert a forcément un impact négatif sur la couverture du code : nous n'avons donc pas deux assert qui vérifient la même condition. Dans le cas contraire, nous avons un jeu de test trop lourd.
  • Les méthodes que nous avons ciblé sont globalement bien couvertes : en particulier les méthodes equals() dans lesquelles beaucoup de if s'enchainent : il faudrait couvrir au moins l'ensemble des cas non triviaux (un objet est null)
  • Aucune méthode get ou set n'a été testée, ni les constructeurs. Ces méthodes fonctionnent forcément. Une erreur classique est d'appeler un setter quelconque setValeur("valeur") et de faire un Assert.assertEquals("valeur", getValeur()) ce test ne peut pas échouer il n'apporte que de la complexité superfue

2. Test des dao

Le test de le couche DAO est plus complexe, il demande de faire appel à une base de données. Nous pouvons pour cela utiliser un schéma dédié de notre base, mais dans le cas présent, nous allons travailler sur une base h2

Le but de cet exercice est d'utiliser une base de données h2 pour tester les daos :

  • fr.julien.formation.basket.dao.BilansDao qui permet d'accéder à la table contenant les bilans des match
  • fr.julien.formation.basket.dao.MatchDao qui permet d'accéder à la table contenant les match
Diagramme de la base de données

Le script SQL suivant permet de charger en base le résultat du dernier match d'Orléans contre limoges

DROP TABLE IF EXISTS matchs;
CREATE TABLE matchs (
	id INT PRIMARY KEY
);
DROP TABLE IF EXISTS equipes;
CREATE TABLE equipes (
	id INT PRIMARY KEY,
	nom VARCHAR
);
DROP TABLE IF EXISTS joueurs;
CREATE TABLE joueurs (
	id INT PRIMARY KEY,
	nom VARCHAR,
	prenom VARCHAR,
	id_equipe INT REFERENCES equipes(id)
);
DROP TABLE IF EXISTS bilans;
CREATE TABLE bilans (
	id_match INT,
	id_joueur INT REFERENCES joueurs(id),
	lancer_francs INT,
	lancer_francs_reussis INT,
	deux_points INT,
	deux_points_reussis INT,
	trois_points INT,
	trois_points_reussis INT,
	rebonds INT,
	fautes INT,
	passes_decisives INT,
	ballons_perdus INT,
	interceptions INT,
	contres INT
);

INSERT INTO equipes(id, nom) 
VALUES 
	(1, 'Orléans'), 
	(2, 'Limoges');
INSERT INTO joueurs (id, nom, prenom, id_equipe)
VALUES 
	(201, 'CAMARA', 'Ousmane', 2),
	(202, 'JONES', 'Joseph', 2),
	(203, 'PREPELIC', 'Klemen', 2),
	(204, 'WOJCIECHOWSKI', 'Mathieu', 2),
	(205, 'WOOD', 'Dashaun', 2),
	(206, 'DELAGE', 'Benjamin', 2),
	(207, 'DUPORT', 'Romain', 2),
	(208, 'FAIR', 'C.J', 2),
	(209, 'MUNANGA', 'Shekinah', 2),
	(210, 'RANDLE', 'Jerome', 2),
	(211, 'ZERBO', 'Fréjus', 2),
	(101, 'DOWNS', 'Micah', 1),
	(102, 'LOUBAKI', 'Luc', 1),
	(103, 'MILOSEVIC', 'Nemanja', 1),
	(104, 'McALARNEY', 'Kyle', 1),
	(105, 'OLASENI', 'Gabe', 1),
	(106, 'JOSEPH', 'Georgi', 1),
	(107, 'MENDY', 'Antoine', 1),
	(108, 'PRINCE', 'John', 1),
	(109, 'SOMMERVILLE', 'Marcellus', 1),
	(110, 'SYLLA', 'Abdel Kader', 1),
	(111, 'VINCENT', 'Thomas', 1);
	
INSERT INTO matchs(id) VALUES (34);

INSERT INTO bilans (id_match, id_joueur, lancer_francs_reussis, lancer_francs, deux_points_reussis, deux_points, trois_points_reussis, trois_points, rebonds, fautes, passes_decisives,ballons_perdus, interceptions, contres)
VALUES 
	(34, 201, 0, 0, 6, 14, 0, 0, 8, 3, 1, 1, 0, 0),
	(34, 202, 0, 1, 2, 3, 0, 0, 0, 2, 1, 1, 0, 0),
	(34, 203, 4, 4, 0, 3, 3, 9, 1, 4, 5, 1, 0, 0),
	(34, 204, 0, 0, 0, 0, 2, 2, 8, 4, 2, 1, 0, 0),
	(34, 205, 0, 0, 2, 4, 1, 7, 2, 3, 2, 3, 3, 0),
	(34, 206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
	(34, 207, 0, 0, 1, 3, 1, 3, 2, 0, 0, 0, 0, 0),
	(34, 208, 2, 4, 3, 4, 0, 3, 5, 1, 0, 0, 1, 1),
	(34, 209, 0, 0, 2, 3, 1, 1, 3, 2, 0, 1, 1, 0),
	(34, 210, 0, 0, 4, 7, 2, 4, 1, 0, 3, 4, 0, 0),
	(34, 211, 3, 4, 1, 3, 0, 0, 1, 0, 0, 0, 1, 0),
	(34, 101, 1, 2, 2, 2, 3, 5, 5, 0, 4, 1, 0, 0),
	(34, 102, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0),
	(34, 103, 0, 0, 2, 2, 1, 2, 1, 1, 1, 0, 0, 0),
	(34, 104, 3, 3, 0, 2, 1, 4, 3, 1, 2, 1, 1, 0),
	(34, 105, 2, 2, 4, 10, 0, 0, 6, 2, 2, 0, 1, 0),
	(34, 106, 0, 0, 1, 1, 1, 1, 3, 2, 1, 1, 1, 0),
	(34, 107, 1, 1, 5, 7, 2, 7, 3, 0, 2, 1, 1, 0),
	(34, 108, 1, 2, 7, 8, 1, 2, 5, 2, 10, 2, 4, 0),
	(34, 109, 4, 4, 4, 6, 0, 1, 3, 3, 3, 2, 0, 0),
	(34, 110, 0, 1, 5, 7, 0, 0, 5, 2, 4, 2, 2, 0),
	(34, 111, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0);

Vous pourrez charger ce fichier soit directement soit créer des dataset et les charger à l'aide de DBUnit

public class BilansDaoTest {

    private Connection cnx;

    @Before
    public void setUp() {
        JdbcDataSource dataSource = new JdbcDataSource();
        dataSource.setURL("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1");
        dataSource.setUser("sa");
        dataSource.setPassword("");
        try {
            cnx = dataSource.getConnection();
            try (InputStreamReader fr = new FileReader(new File("src/test/resources/inti_database.sql")); BufferedReader br = new BufferedReader(fr)) {
                RunScript.execute(cnx, br);
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
	
	@After
    public void tearDown() {
        try {
            cnx.close();
        }
        catch (SQLException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testerSelection() {
        try {
            List bilans = BilansDao.getInstance().getBilansByMatch(cnx, 34);
            Assert.assertEquals(22, bilans.size());
            Assert.assertEquals(new Joueur("CAMARA", "Ousmane", new Equipe("Limoges")), bilans.get(0).getJoueur());
            Assert.assertEquals(0, bilans.get(0).getLancerFrancsReussis());
            Assert.assertEquals(0, bilans.get(0).getLancerFrancs());
            Assert.assertEquals(6, bilans.get(0).getDeuxPointsReussis());
            Assert.assertEquals(14, bilans.get(0).getDeuxPoints());
            Assert.assertEquals(0, bilans.get(0).getTroisPointsReussis());
            Assert.assertEquals(0, bilans.get(0).getTroisPoints());
            Assert.assertEquals(1, bilans.get(0).getPassesDecisives());
            Assert.assertEquals(1, bilans.get(0).getBallonsPerdus());
            Assert.assertEquals(3, bilans.get(0).getFautes());
            Assert.assertEquals(8, bilans.get(0).getRebonds());
            Assert.assertEquals(0, bilans.get(0).getInterceptions());
            Assert.assertEquals(0, bilans.get(0).getContres());
        }
        catch (BasketException e) {
            e.printStackTrace();
            Assert.fail();
        }
    }

    @Test
    public void testerInsertion() {
        try {
            try (Statement stmt = cnx.createStatement()) {
                stmt.executeUpdate("INSERT INTO joueurs(id, nom, prenom, id_equipe) VALUES (0, 'Gauchet', 'Julien', 2)");
            }
            BilanJoueur b = new BilanJoueur(new Joueur("Gauchet", "Julien", new Equipe("Orléans")), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
            BilansDao.getInstance().inserer(cnx, b, 34);
            try (Statement stmt = cnx.createStatement(); ResultSet rs = stmt.executeQuery("SELECT * FROM bilans WHERE id_joueur=0")) {
                Assert.assertTrue(rs.next());
                Assert.assertEquals(2, rs.getInt("lancer_francs_reussis"));
            }
        }
        catch (BasketException | SQLException e) {
            e.printStackTrace();
            Assert.fail();
        }
    }
}

public class MatchsDaoTest {

    private Connection cnx;

    @Before
    public void setUp() {
        JdbcDataSource dataSource = new JdbcDataSource();
        dataSource.setURL("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1");
        dataSource.setUser("sa");
        dataSource.setPassword("");
        try {
            cnx = dataSource.getConnection();
            try (InputStreamReader fr = new FileReader(new File("src/test/resources/inti_database.sql")); BufferedReader br = new BufferedReader(fr)) {
                RunScript.execute(cnx, br);
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
	
	@After
    public void tearDown() {
        try {
            cnx.close();
        }
        catch (SQLException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testerInsertion() {
        try {
            MatchDao.getInstance().inserer(cnx, 1);
            try (Statement stmt = cnx.createStatement()) {
                try (ResultSet rs = stmt.executeQuery("SELECT * FROM matchs WHERE id=1")) {
                    Assert.assertTrue(rs.next());
                }
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3. Test des services avec Mock

Nous allons maintenant tester la classe fr.julien.formation.basket.services.MiseAJourMatchs qui fait appel à un web service non accessible hors production. Utilisez des mock pour réaliser le test de cette classe. Un refactoring est nécéssaire

Le web service fournit un résultat xml scructuré de la facon suivante :

<matchs journee="??">
	nomJoueur;prenomJoueur;nomEquipe;lancerFrancs;lancerFrancsReussis;deuxPoints;deuxPointsReussis;troisPoints;troisPointsReussis;rebonds;fautes;passesDecisives;ballonsPerdus;interceptions;contres
	nomJoueur;prenomJoueur;nomEquipe;lancerFrancs;lancerFrancsReussis;deuxPoints;deuxPointsReussis;troisPoints;troisPointsReussis;rebonds;fautes;passesDecisives;ballonsPerdus;interceptions;contres
</matchs>
/**
 * Classe permettant d'accéder au web service de la LNB
 * @author Julien Gauchet
 */
public class WebServiceLNBProxy {

    private static WebServiceLNBProxy instance = new WebServiceLNBProxy();

    private WebServiceLNBProxy() {
        super();
    }

    /**
     * Méthode permettant d'accéder au web service de la LNB
     * @param url
     *            l'url du web service
     * @param journee
     *            La journée recherchée
     * @return la réponse au format xml
     * @throws BasketException
     */
    public String getReponse(String url, int journee) throws BasketException {
        String res = null;
        try {
            HttpGet httpget = new HttpGet(url + journee);
            HttpClient httpclient = new DefaultHttpClient();
            HttpResponse response = httpclient.execute(httpget);
            res = EntityUtils.toString(response.getEntity());
        }
        catch (IOException e) {
            throw new BasketException(e.getMessage(), e);
        }
        return res;
    }

    /**
     * Méthode permettant d'accéder à l'instance de {@link WebServiceLNBProxy}
     * @return l'instance de {@link WebServiceLNBProxy}
     */
    public static WebServiceLNBProxy getInstance() {
        return instance;
    }
}


/**
 * Service permettant d'insérer dans la base de données les nouveaux match en accédant à un web service mis en place par la LNB.
 * Ce web service n'est accessible qu'en production
 * @author Julien Gauchet
 */
public class MiseAJourMatchs {

    private static MiseAJourMatchs instance = new MiseAJourMatchs();
	private WebServiceLNBProxy webService;

    private MiseAJourMatchs() {
        webService = WebServiceLNBProxy.getInstance();
    }

    /**
     * Cette méthode permet d'insérer dans la base les matchs d'une journée donnée en accédant au web service de la LNB. La réponse est sous la forme :
     * <matchs journee="??">
     * nomJoueur;prenomJoueur;nomEquipe;lancerFrancs;lancerFrancsReussis;deuxPoints;deuxPointsReussis;troisPoints;troisPointsReussis;rebonds;fautes;passesDecisives;ballonsPerdus;interceptions;contres
     * nomJoueur;prenomJoueur;nomEquipe;lancerFrancs;lancerFrancsReussis;deuxPoints;deuxPointsReussis;troisPoints;troisPointsReussis;rebonds;fautes;passesDecisives;ballonsPerdus;interceptions;contres
     * </matchs>
     * @param cnx
     * @param equipe
     * @param journee
     * @throws BasketException
     */
    public void mettreAJour(Connection cnx, Equipe equipe, int journee) throws BasketException {
		String reponse = webService.getReponse("http://www.lnb.fr/ws/journee/", journee);
        String[] in = reponse.substring(20, reponse.length() - 9).split(";");
        List infos = new ArrayList<>();
        infos.addAll(Arrays.asList(in));
        while (!infos.isEmpty()) {
            BilanJoueur b = new BilanJoueur(new Joueur(infos.remove(0), infos.remove(0), new Equipe(infos.remove(0))), Integer.parseInt(infos.remove(0)), Integer.parseInt(infos.remove(0)), Integer.parseInt(infos.remove(0)), Integer.parseInt(infos.remove(0)), Integer.parseInt(infos.remove(0)), Integer.parseInt(infos.remove(0)), Integer.parseInt(infos.remove(0)), Integer.parseInt(infos.remove(0)), Integer.parseInt(infos.remove(0)), Integer.parseInt(infos.remove(0)), Integer.parseInt(infos.remove(0)), Integer.parseInt(infos.remove(0)));
            BilansDao.getInstance().inserer(cnx, b, journee);
        }
    }
	
	/**
     * Méthode permettant de définir le proxy d'accès du web service de la LNB
     * @param webService
     *            le proxy d'accès du web service de la LNB
     */
    public void setWebService(WebServiceLNBProxy webService) {
        this.webService = webService;
    }

    /**
     * Méthode permettant d'accéder à l'instance de {@link MiseAJourMatchs}
     * @return l'instance de {@link MiseAJourMatchs}
     */
    public static MiseAJourMatchs getInstance() {
        return instance;
    }
}

public class MiseAJourMatchsTest {

    private Connection cnx;

    @Before
    public void setUp() {
        JdbcDataSource dataSource = new JdbcDataSource();
        dataSource.setURL("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1");
        dataSource.setUser("sa");
        dataSource.setPassword("");
        try {
            cnx = dataSource.getConnection();
            try (InputStreamReader fr = new FileReader(new File("src/test/resources/inti_database_2.sql")); BufferedReader br = new BufferedReader(fr)) {
                RunScript.execute(cnx, br);
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

    @After
    public void tearDown() {
        try {
            cnx.close();
        }
        catch (SQLException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testerMiseAJour() {
        try {
            WebServiceLNBProxy webService = Mockito.mock(WebServiceLNBProxy.class);
            StringBuilder sb = new StringBuilder();
            sb.append("");
            sb.append("SOMMERVILLE;Marcellus;Orléans;5;3;5;5;2;1;3;2;3;1;0;1");
            sb.append("");
            Mockito.when(webService.getReponse("http://www.lnb.fr/ws/journee/", 33)).thenReturn(sb.toString());
            MiseAJourMatchs.getInstance().setWebService(webService);
            MiseAJourMatchs.getInstance().mettreAJour(cnx, new Equipe("Orléans"), 33);
            try (Statement stmt = cnx.createStatement()) {
                try (ResultSet rs = stmt.executeQuery("SELECT * FROM bilans WHERE id_match=33")) {
                    Assert.assertTrue(rs.next());
                    Assert.assertEquals(5, rs.getInt("lancer_francs"));
                    Assert.assertEquals(3, rs.getInt("lancer_francs_reussis"));
                    Assert.assertEquals(5, rs.getInt("deux_points"));
                    Assert.assertEquals(5, rs.getInt("deux_points_reussis"));
                    Assert.assertEquals(2, rs.getInt("trois_points"));
                    Assert.assertEquals(1, rs.getInt("trois_points_reussis"));
                    Assert.assertEquals(3, rs.getInt("rebonds"));
                    Assert.assertEquals(2, rs.getInt("fautes"));
                    Assert.assertEquals(3, rs.getInt("passes_decisives"));
                    Assert.assertEquals(1, rs.getInt("ballons_perdus"));
                    Assert.assertEquals(0, rs.getInt("interceptions"));
                    Assert.assertEquals(1, rs.getInt("contres"));
                }
            }
        }
        catch (Exception e) {
            e.printStackTrace();
            Assert.fail();
        }
    }
}

public class MiseAJourMatchsTest {

    private Connection cnx;

    @Before
    public void setUp() {
        JdbcDataSource dataSource = new JdbcDataSource();
        dataSource.setURL("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1");
        dataSource.setUser("sa");
        dataSource.setPassword("");
        try {
            cnx = dataSource.getConnection();
            try (InputStreamReader fr = new FileReader(new File("src/test/resources/inti_database_2.sql")); BufferedReader br = new BufferedReader(fr)) {
                RunScript.execute(cnx, br);
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

    @After
    public void tearDown() {
        try {
            cnx.close();
        }
        catch (SQLException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testerMiseAJour() {
        try {
            WebServiceLNBProxy webService = new WebServiceLNBProxy() {

                @Override
                public String getReponse(String url, int journee) {
                    StringBuilder sb = new StringBuilder();
                    sb.append("");
                    sb.append("SOMMERVILLE;Marcellus;Orléans;5;3;5;5;2;1;3;2;3;1;0;1");
                    sb.append("");
                    return sb.toString();
                }
            };
            MiseAJourMatchs.getInstance().setWebService(webService);
            MiseAJourMatchs.getInstance().mettreAJour(cnx, new Equipe("Orléans"), 33);
            try (Statement stmt = cnx.createStatement()) {
                try (ResultSet rs = stmt.executeQuery("SELECT * FROM bilans WHERE id_match=33")) {
                    Assert.assertTrue(rs.next());
                    Assert.assertEquals(5, rs.getInt("lancer_francs"));
                    Assert.assertEquals(3, rs.getInt("lancer_francs_reussis"));
                    Assert.assertEquals(5, rs.getInt("deux_points"));
                    Assert.assertEquals(5, rs.getInt("deux_points_reussis"));
                    Assert.assertEquals(2, rs.getInt("trois_points"));
                    Assert.assertEquals(1, rs.getInt("trois_points_reussis"));
                    Assert.assertEquals(3, rs.getInt("rebonds"));
                    Assert.assertEquals(2, rs.getInt("fautes"));
                    Assert.assertEquals(3, rs.getInt("passes_decisives"));
                    Assert.assertEquals(1, rs.getInt("ballons_perdus"));
                    Assert.assertEquals(0, rs.getInt("interceptions"));
                    Assert.assertEquals(1, rs.getInt("contres"));
                }
            }
        }
        catch (Exception e) {
            e.printStackTrace();
            Assert.fail();
        }
    }
}

4. Que faire de l'ihm ?

Notre application contient une partie ihm : le test de l'ihm ne se fait pas grâce à des tests unitaires. Cependant, une partie du code de l'ihm peut être testée : a vous de l'identifier et de faire ce qu'il faut pour que cette partie soit désormais testable

/**
 * Classe permettant de définir le tableau de l'équipe
 * @author Julien Gauchet
 */
public class TableauEquipe {

    private String nomEquipe;
    private List> statistiques;

    public TableauEquipe(String nomEquipe) {
        this.nomEquipe = nomEquipe;
        this.statistiques = new ArrayList<>();
    }

    /**
     * Méthode permettant d'accéder au nom de l'équipe
     * @return le nom de l'équipe
     */
    public String getNomEquipe() {
        return nomEquipe;
    }

    /**
     * Méthode permettant d'accéder aux statistiques
     * @return les statistiques
     */
    public List> getStatistiques() {
        return statistiques;
    }
}

/**
 * Classe permettant de définir le tableau de match
 * @author Julien Gauchet
 */
public class TableauMatch {

    private TableauEquipe tableauEquipe1;
    private TableauEquipe tableauEquipe2;

    public TableauMatch(TableauEquipe tableauEquipe1, TableauEquipe tableauEquipe2) {
        super();
        this.tableauEquipe1 = tableauEquipe1;
        this.tableauEquipe2 = tableauEquipe2;
    }

    /**
     * Méthode permettant d'accéder au tableau de l'équipe 1
     * @return le tableau de l'équipe 1
     */
    public TableauEquipe getTableauEquipe1() {
        return tableauEquipe1;
    }

    /**
     * Méthode permettant d'accéder tableau de l'équipe 2
     * @return le tableau de l'équipe 2
     */
    public TableauEquipe getTableauEquipe2() {
        return tableauEquipe2;
    }
}

/**
 * Service permettant de calculer des statistiques sur les match
 * @author Julien Gauchet
 */
public class CalculStatistiquesService {

    private static CalculStatistiquesService instance = new CalculStatistiquesService();

    private CalculStatistiquesService() {
        super();
    }

    /**
     * Méthode permettant de calculer le nombre de points marqués par un joueur
     * @param bilan
     *            Le bilan du joueur sur le match
     * @return le score du joueur
     */
    public int calculerScore(BilanJoueur bilan) {
        int score = 0;
        score += bilan.getDeuxPointsReussis() * 2;
        score += bilan.getTroisPointsReussis() * 3;
        score += bilan.getLancerFrancsReussis();
        return score;
    }

    /**
     * Méthode permettant de calculer l'évaluation d'un joueur sur un match
     * @param b
     *            Le bilan du joueur
     * @return l'évaluation
     */
    public int calculerEvaluation(BilanJoueur b) {
        int eval = 0;
        eval += calculerScore(b);
        eval += b.getRebonds();
        eval += b.getPassesDecisives();
        eval += b.getInterceptions();
        eval += b.getContres();
        eval += b.getDeuxPointsReussis();
        eval += b.getTroisPointsReussis();
        eval += b.getLancerFrancsReussis();
        eval -= b.getDeuxPoints();
        eval -= b.getTroisPoints();
        eval -= b.getLancerFrancs();
        eval -= b.getBallonsPerdus();
        return eval;
    }

    /**
     * Méthode permettant d'accéder à l'instance de {@link CalculStatistiquesService}
     * @return l'instance de {@link CalculStatistiquesService}
     */
    public static CalculStatistiquesService getInstance() {
        return instance;
    }
}

/**
 * {@link ActionListener} permettant d'afficher le résultat d'une recherche de match dans la base de données
 * @author Julien Gauchet
 */
public class ListenerRecherche implements ActionListener {

    private TableauExtensible tableauEquipe1;
    private TableauExtensible tableauEquipe2;
    private JTextField journee;
    private Connection cnx;

    /**
     * Constructeur de {@link ListenerRecherche}
     * @param cnx
     *            La connexion à la base de données
     * @param tableauEquipe1
     *            Le tableau de l'équipe 1
     * @param tableauEquipe2
     *            Le tableau de l'équipe 2
     * @param journee
     *            Le numéro de la jourée concernée
     */
    public ListenerRecherche(Connection cnx, TableauExtensible tableauEquipe1, TableauExtensible tableauEquipe2, JTextField journee) {
        this.tableauEquipe1 = tableauEquipe1;
        this.tableauEquipe2 = tableauEquipe2;
        this.journee = journee;
        this.cnx = cnx;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        try {
            TableauMatch tableau = GenerationTableauxService.getInstance().genererTableauMatch(cnx, Integer.parseInt(journee.getText()));
            tableauEquipe1.getEquipe().setText(" " + tableau.getTableauEquipe1().getNomEquipe());
            tableauEquipe2.getEquipe().setText(" " + tableau.getTableauEquipe2().getNomEquipe());
            for (List l : tableau.getTableauEquipe1().getStatistiques()) {
                tableauEquipe1.ajouter(l.toArray());
            }
            for (List l : tableau.getTableauEquipe2().getStatistiques()) {
                tableauEquipe2.ajouter(l.toArray());
            }
        }
        catch (NumberFormatException | BasketException e1) {
            JOptionPane.showMessageDialog(null, "Impossible de charger les données demandées", "Erreur lors du chargment", JOptionPane.ERROR_MESSAGE);
        }
    }
}

public class GenerationTableauxServiceTest {

    private Connection cnx;

    @Before
    public void setUp() {
        JdbcDataSource dataSource = new JdbcDataSource();
        dataSource.setURL("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1");
        dataSource.setUser("sa");
        dataSource.setPassword("");
        try {
            cnx = dataSource.getConnection();
            try (InputStreamReader fr = new FileReader(new File("src/test/resources/inti_database.sql")); BufferedReader br = new BufferedReader(fr)) {
                RunScript.execute(cnx, br);
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

    @After
    public void tearDown() {
        try {
            cnx.close();
        }
        catch (SQLException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testerGenerationTableaux() {
        try {
            TableauMatch t = GenerationTableauxService.getInstance().genererTableauMatch(cnx, 34);
            Assert.assertEquals(true, t.getTableauEquipe1() != null);
            Assert.assertEquals(true, t.getTableauEquipe2() != null);
            Assert.assertEquals("Limoges", t.getTableauEquipe1().getNomEquipe());
            Assert.assertEquals(11, t.getTableauEquipe1().getStatistiques().size());
            int cpt = 0;
            Assert.assertEquals("Ousmane CAMARA", t.getTableauEquipe1().getStatistiques().get(0).get(cpt++));
            Assert.assertEquals("12", t.getTableauEquipe1().getStatistiques().get(0).get(cpt++));
            Assert.assertEquals("6/14", t.getTableauEquipe1().getStatistiques().get(0).get(cpt++));
            Assert.assertEquals("0/0", t.getTableauEquipe1().getStatistiques().get(0).get(cpt++));
            Assert.assertEquals("0/0", t.getTableauEquipe1().getStatistiques().get(0).get(cpt++));
            Assert.assertEquals("8", t.getTableauEquipe1().getStatistiques().get(0).get(cpt++));
            Assert.assertEquals("1", t.getTableauEquipe1().getStatistiques().get(0).get(cpt++));
            Assert.assertEquals("3", t.getTableauEquipe1().getStatistiques().get(0).get(cpt++));
            Assert.assertEquals("0", t.getTableauEquipe1().getStatistiques().get(0).get(cpt++));
            Assert.assertEquals("1", t.getTableauEquipe1().getStatistiques().get(0).get(cpt++));
            Assert.assertEquals("0", t.getTableauEquipe1().getStatistiques().get(0).get(cpt++));
            Assert.assertEquals("12", t.getTableauEquipe1().getStatistiques().get(0).get(cpt++));
        }
        catch (Exception e) {
            e.printStackTrace();
            Assert.fail();
        }
    }
}

5. Bilan de l'exercice

Nous avons testé notre application de manière méticuleuse et sans trop en faire, malgré tout, le refactoring et l'adaptation de l'application à nos test a été une part importante du travail de test, sans doute l'étape la plus longue et complexe

Les sources de la solution sont disponnibles ici : projet basket : solution, le pom utilisé est le suivant : projet basket : solution

La couverture de test est de 51,1% ce qui est un bon score mais encore loin des 80% recommandés. La question la plus importante à se poser n'est pas "quel est ma couverture de test ?" mais "est-ce que je couvre une partie suffisante des fonctionnalités de l'application ?" et dans notre cas, nous ne pouvons pas réelement faire mieux sans tester des choses triviales ou sans dégrader la simplicité de nos tests

Couverture de test