Table of Contents

Tests d'intégration et conception

Ce TD vise

  1. à vous apprendre à mettre en place des tests d'intégration
  2. à concevoir une petite application à plusieurs en prévoyant les tests d'intégration.

Partie 1 : Tutoriel EasyMock (1h grand maximum)

Si vous dépassez le temps passez à la suite et revenez dessus plus tard. L'énoncé suivant est issu du “getting started” de easyMock mis à jour pour travailler avec junit 5 et voir un peu plus de choses.

  1. Voici le .jar dont vous avez besoin pour avoir accès à l'environnement EasyMock.
  2. Créer un projet java
  3. Ajouter à votre classpath du projet le .jar donné ci-dessus : sur le nom du projet > Properties > Java Build Path > Puis ajouter le .jar ci-dessus.
  4. Voici l'interface dont dépendent vos codes, mais que vous ne devez pas implémenter. Ajoutez la à votre projet.
    public interface Collaborator {
     
    	// if the document already exists, a "AlreadyAdded" exception is thrown.
    	// if the document fails to be added, false is return.
    	public boolean documentAdded(String title) throws AlreadyAdded   ;
    	public void documentRemoved(String title) ;
     
    }

    Et l'exception associée :

    public class AlreadyAdded extends Exception {
    } 
  5. Voici vos codes (donc vous pouvez bien sûr les modifier si vous le voulez) et donc il s'agit bien de la classe à tester
    public class ClassTested {
     
    	public static  final String COPY = "_copy";
    	private Collaborator listener;
     
    	private HashMap<String, String> documents = new HashMap<>();
     
    	public void setListener(Collaborator listener) {
    		this.listener = listener;
    	}
     
    	public void addDocument(String title, String document) {
    		try {
    			if (listener.documentAdded(title) ) 
    				documents.put(title, document);
    		} catch (AlreadyAdded e) {
    			documents.put(title+COPY, document);
    		}
    	}
     
    	public void removeDocument(String title) {
    		listener.documentRemoved(title);
    	}
     
     
    	public Collaborator getListener() {
    		return listener;
    	}
     
    	public boolean isContained(String key) {
    		return documents.containsKey(key);
     
    	}
    }
  6. Voici un début de tests.
    1. Remarquez la construction du mock (5.a)
       import static org.easymock.EasyMock.*;
      import static org.junit.Assert.assertFalse;
      import static org.junit.jupiter.api.Assertions.assertTrue;
       
      import org.easymock.EasyMockSupport;
      import org.easymock.Mock;
      import org.easymock.TestSubject;
      import org.junit.jupiter.api.BeforeEach;
      import org.junit.jupiter.api.Test;
       
       
       
      public class ExampleTest extends EasyMockSupport {
       
      	  @TestSubject
      	  private ClassTested classUnderTest = new ClassTested(); // 2
       
      	  @Mock
      	  private Collaborator mock; // 1
       
      	  @BeforeEach
      	  public void setUp() {
                      //5.a
      		mock = mock(Collaborator.class); 
      		classUnderTest = new ClassTested();
      		classUnderTest.setListener(mock);
      	  }
       
    2. Vous pouvez l'exécuter il ne se passe rien (il n'y a aucun test 8-) )
  7. Ajoutez un test.
        @Test
    	  public void testRemoveNonExistingDocument() {
    	    // This call should not lead to any notification
    	    // of the Mock Object
    		  replay(mock); // 6.b
    		  classUnderTest.removeDocument("Does not exist");
    	  }
    1. Il échoue en effet on enregistre (6.b) que le mock ne reçoit aucun message alors que là il a reçu un message. Vous devrez donc avoir l'erreur suivante
       java.lang.AssertionError: 
        Unexpected method call Collaborator.documentRemoved("Does not exist"):...
  8. Ajoutez un test, cette fois-ci juste :
    1. On déclare le message que doit recevoir le mock (7.a)
    2. On enregistre (7.b)
    3. On lance le test sur notre code (7.c)
    4. On explicite la vérification (réalisée par défaut) (7.d)
          @Test
      	  public void testRemoveNonExistingDocument2() {
      		  mock.documentRemoved("Does not exist"); //7.a
      		  replay(mock); //7.b
      		  classUnderTest.removeDocument("Does not exist"); //7.c
      		  verify(mock); //7.d
      	  }
  9. Ajoutez un test, mais cette fois-ci nous explicitons la valeur de retour attendue et nous créons deux mocks pour nous assurer qu'il n'y a pas d'effets secondaires
    	  @Test
    	  public void testAddDocument() throws AlreadyAdded {
    		  //Initialisation
    		  Collaborator firstCollaborator = mock(Collaborator.class);//construction de mock
    		  Collaborator  secondCollaborator = mock(Collaborator.class);//construction de mock, il ne sera pas utilisé
    		  classUnderTest.setListener(firstCollaborator); 
     
    		  //// expect document addition
    		  expect(firstCollaborator.documentAdded("New Document")).andReturn(true); //On attend que le mock réponde True ! 
    		  replayAll(); //on enregistre le comportement de tous les Mocks
    		  classUnderTest.addDocument("New Document", "content");
    		  assertTrue(classUnderTest.isContained("New Document")); //on vérifie que NOS codes se comportent correctement
    		  verifyAll(); //On vérifie le comportement de tous les mocks
    	  }
  10. Ajoutez un test, mais cette fois-ci nous attendons pour valeur de retour false
     	  @Test
    	  public void testFailingAddDocument() throws AlreadyAdded {
    		  //Initialisation
    		  Collaborator firstCollaborator = mock(Collaborator.class);
    		  Collaborator secondCollaborator = mock(Collaborator.class);
    		  classUnderTest.setListener(firstCollaborator); 
     
    		  //// expect document addition
    		  expect(firstCollaborator.documentAdded("New Document")).andReturn(false);
    		  replayAll();
    		  classUnderTest.addDocument("New Document", "content");
    		  assertFalse(classUnderTest.isContained("New Document"));
    		  verifyAll();
    	  }
     
  11. et enfin nous testons une levée d'exception
     	  @Test
    	  public void testDuplicationWhenAddingDocument() throws AlreadyAdded {
    		  //Initialisation
    		  Collaborator firstCollaborator = mock(Collaborator.class);
    		  Collaborator secondCollaborator = mock(Collaborator.class);
    		  classUnderTest.setListener(firstCollaborator); 
     
    		  //// expect document addition
    		  expect(firstCollaborator.documentAdded("New Document")).andThrow(new AlreadyAdded());
    		  replayAll();
    		  classUnderTest.addDocument("New Document", "content");
    		  assertTrue(classUnderTest.isContained("New Document"+ClassTested.COPY));
    		  verifyAll();
    	  }

Cela conclut la partie tutorielle. A présent, vous devriez savoir créer vous même des tests d'intégration.

Partie 2 : Un jeu de Quizz

Vous devez réaliser en groupe de X étudiants un jeu de quizz dont voici la spécification.

Spécification

Modélisation

Exigences

Voici les interfaces qui vous sont données et que vous devez respecter.

public interface GameInterface {
 
	void startGame();
 
	boolean isNotOver();
 
	String nextQuestion();
 
	boolean setCurrentUserAnswer(String answer);
 
	String getRightAnswer();
 
	int getPoints();
 
}
public interface QuizInterface {
 
	public String getQuestion(int currentQuestionNumber) ;
 
	public boolean isGoodAnswer(int currentQuestionNumber, String answer);
 
	public String getAnswer(int currentQuestionNumber);
 
	public int size();
 
	public void addQuestion(QuestionInterface q1);
 
}
public interface QuestionInterface {
 
	String getAnswer();
 
	String getQuestion();
 
	boolean isGoodAnswer(String answer);
 
}

Voici un code pour tester un jeu.

package quizzPK;
 
import java.util.Scanner;
 
public class mainTestGame {
 
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
 
		QuizInterface quiz = new Quiz();
		QuestionInterface q1 = new Question("Capitale de la France ?", "Paris");
		QuestionInterface q2 = new Question("Capitale de l'Allemagne ?", "Berlin");
		QuestionInterface q3 = new Question("Capitale de l'Italie", "Rome");
 
		quiz.addQuestion(q1);
		quiz.addQuestion(q2);
		quiz.addQuestion(q3);
		GameInterface game = new Game(quiz);
 
		game.startGame();
 
		while (game.isNotOver()) {
			System.out.println(game.nextQuestion() + " : ") ;
			String answer = sc.nextLine();
			boolean valid = game.setCurrentUserAnswer(answer);
			if (!valid ) {
				System.out.println("You failed, the correct answer is : " + game.getRightAnswer() );
			}
			else
				System.out.println("Well done ! ");
		}
 
		System.out.println("Score : " + game.getPoints());
	}
 
 
 
}

A Faire

  1. Modélisez par groupe de 2 ou 3 étudiants, le jeu
    1. En particulier, intéressez-vous aux interactions entre les classes.
    2. Une fois que vous êtes d'accord, vous passez à la suite
  2. Développez séparément
    1. Etudiant 1 : Développez la classe Game sans développer la classe Quiz.
      1. Tester votre classe Game en utilisant des Mocks.
    2. Etudiant 2 : Développez la classe Quizz sans développer la classe Question.
      1. Tester votre classe Quizz en utilisant des Mocks
  3. Intégrez vos codes.

L'essentiel n'est pas d'atteindre cette ultime étape. Mais davantage d'apprendre à écrire des tests d'intégration.