Seven Wonders 4 – la couche de service

Passons au module business. Nous allons y créer notre premier service. Pour Partie je vais faire une interface PartieManager et une implémentation PartieManagerImpl. Notre partie doit pouvoir faire les 4 actions possibles :

  1. construire un étage avec une carte en payant le coût
  2. jouer une carte puis effectuer l’effet
  3. exécuter l’action « défausse une carte pour 3 pièces »
  4. faire une « action spéciale » relative à une merveille.

Pour l’instant, faisons comme si les faces B des merveilles n’existaient pas. Ces faces B offrent des pouvoirs spéciaux en delà de ces 3 actions. Elles seront l’occasion de faire un peu de refactoring… Commençons par définir une action : d’abord l’enum spécifiant quelle action est faite :


public enum TypeAction {
	Joue, Defausse, Merveille, Special
}

Puis l’action qui est donc définie par le joueur qui la fait, le type d’action et d’autres paramètres que nous ajouterons au fur et à mesure, mais le plus évident et commun au cas 1, 2 et 3, c’est que l’action portera toujours sur un carte (en pratique, les actions spéciales également).

public class Action {
	Joueur joueur;

	TypeAction typeAction;

	Carte carte;
}

Ces 2 classes vont dans sevenwonders-common. Reprenons notre PartieManager : Il faut qu’il puisse effectuer une action. Repartons sur du TDD mais plus précisément que pour les modèles (il y avait des approximation et l’oubli de la phase de refactoring); D’abord le code (ici l’interface et l’implémentation) :

public interface PartieManager {
  public void effectueAction(Partie partie, Action action);
}

public class PartieManagerImpl implements PartieManager {
  @Override
  public void effectueAction(Partie partie, Action action) {
  }
}

Et nous allons faire pour débuter les tests sur la défausse : 1 réussie qui donne 3 pièces et met la carte à la défausse, et une ratée qui doit lever une exception :

public class PartieManagerImplTest {

  private Partie partie;

  private Joueur joueurA;

  private Carte carteScierie, carteUniversite;

  private PartieManagerImpl partieManager;

  @Before
  public void setUp() {
    partieManager = new PartieManagerImpl();
    Merveille merveilleA = new Merveille("A", "A", 1, "", null, new Cout[0]);
    partie = new Partie();
    partie.addJoueur(joueurA = new Joueur(merveilleA));
    joueurA.getMain().add(carteScierie = new Carte(TypeCarte.MatierePremiere, "Sawmill", "Scierie", new Cout(1), null, "Fournit 2 bois"));
    joueurA.getMain().add(new Carte(TypeCarte.Science, "Library", "Bibliothèque", new Cout(0, Ressource.Pierre, Ressource.Pierre, Ressource.Tissu), null, "Ecriture"));
    carteUniversite = new Carte(TypeCarte.Science, "University", "Université", new Cout(0, Ressource.Bois, Ressource.Bois, Ressource.Papyrus, Ressource.Verre), null, "Ecriture");
  }

  @Test
  public void testDefausseReussie() throws Exception {
    Action action = new Action(joueurA, TypeAction.Defausse, carteScierie);

    // on vérifie la configuration de départ
    assertEquals(0, partie.getDefausse().size());
    assertEquals(3, joueurA.getNombrePieces().intValue());
    assertEquals(2, joueurA.getMain().size());
    partieManager.effectueAction(partie, action);
    // le joueur gagne 3 pièces, et met une carte en défausse
    assertEquals(6, joueurA.getNombrePieces().intValue());
    assertEquals(1, partie.getDefausse().size());
    assertEquals(carteScierie, partie.getDefausse().get(0));
    assertEquals(1, joueurA.getMain().size());
  }

  @Test(expected=Exception.class)
  public void testDefausseImpossible() throws Exception {
    Action action = new Action(joueurA, TypeAction.Defausse, carteUniversite);
    partieManager.effectueAction(partie, action);
  }
}

Le test plante, la fonction est vide, tout est normal. Ecrivons donc la fonction :

  @Override
  public void effectueAction(Partie partie, Action action) throws Exception {

      if (action.getJoueur().getMain().contains(action.getCarte())) {
        action.getJoueur().getMain().remove(action.getCarte());
        partie.getDefausse().add(action.getCarte());
        action.getJoueur().modifieNombrePieces(3);
      } else {
        throw new Exception("Le joueur ne possede pas la carte " + action.getCarte());
      }
 }

Notez qu’on ne teste pas le type de l’action, et c’est voulu ; ceci viendra avec les autres tests ; pour l’instant, le TDD nous fait écrire la fonction minimale. Celle-ci passe le test : un peu de refactoring, on externalise le joueur et la carte pour plus de lisibilité et on vérifie que tout est vert.

@Override
  public void effectueAction(Partie partie, Action action) throws Exception {
    Joueur joueur = action.getJoueur();
    Carte carte = action.getCarte();

    if (joueur.getMain().contains(carte)) {
      joueur.getMain().remove(carte);
      partie.getDefausse().add(carte);
      joueur.modifieNombrePieces(3);
    } else {
      throw new Exception("Le joueur ne possede pas la carte " + carte);
    }
  }

Pour accélérer un peu nous allons juste décrire la suite sans coller tout le code et les tests correspondants : Pour les autres action et payer son cout, un joueur peut utiliser ses pièces à lui, ses ressources, et donner des pièces à ses voisins de droite ou gauche pour leur acheter des ressources :

public class ChoixAchatRessources {
	Integer piecesPourBanque = 0;

	List ressourcesDroite = new ArrayList();
	List ressourcesGauche = new ArrayList();
	List ressourcesSoi = new ArrayList();

	Integer piecesPourGauche = 0;
	Integer piecesPourDroite = 0;
}

On écrit ensuite la fonction qui fait payer un cout à un joueur et les tests correspondants.

public enum Place {
  Gauche, Droite, Soi
}

@Override
  public void paieCout(Partie partie, Joueur joueur, ChoixAchatRessources cout) {

  }

Bon j’accélère un poil sinon nous y serons encore dans 6 mois : je développe les autres fonctions utiles. A un moment j’ai besoin d’avoir spécifiquement la liste des cartes, pour coder les tests du type « telle carte donne 2 pts de victoire » ou « telle carte donne 3 en puissance militaire ». Nous allons développer les cartes et les merveilles mais en spring beans, pas dans une base de données ; plusieurs raisons : les cartes et merveilles sont statiques et on peut ainsi voir la gestion des beans spring.

Un dernier exemple avec mockito cette fois : nous allons tester la carte qui calcule la puissance militaire d’un joueur. Facile : il faut faire la somme de ses médailles… sauf s’il a des cartes militaires en jeu, ou s’il a construit le 2ème étage de la merveille Colosse de Rhodes. On peut donc créer une partie avec ces joueurs, ces merveilles, ces cartes et tester tout ce bousin, ou se contenter de mocker la partie pour qu’elle réponde « oui » à « est ce que le joueur a construit une caserne » et à « est ce que le joueur a le colosse de Rhodes et a construit le 2eme étage.

Donc : de base, la puissance est de 0, -1 par médaille perdante, +1 par médaille de victoire de l’age 1, +3 par médaille de victoire de l’age 3, et +5 par médaille de victoire de l’age 3:

@Test
  public void testCalculPuissanceMilitaire1() {
    assertEquals(0, partieManager.calculePuissanceMilitaire(partie, joueurA));
  }
  
  @Test
  public void testCalculPuissanceMilitaire2() {
    joueurA.ajouteMedaille(Medaille.Defaite);
    assertEquals(-1, partieManager.calculePuissanceMilitaire(partie, joueurA));
  }

  @Test
  public void testCalculPuissanceMilitaire3() {
    joueurA.ajouteMedaille(Medaille.VictoireII);
    joueurA.ajouteMedaille(Medaille.VictoireIII);
    assertEquals(8, partieManager.calculePuissanceMilitaire(partie, joueurA));
  }

  @Test
  public void testCalculPuissanceMilitaire() {
    Joueur mockedJoueur = Mockito.mock(Joueur.class);
    Merveille mockedMerveille = Mockito.mock(Merveille.class);
    mockedJoueur.ajouteMedaille(Medaille.Defaite);
    Mockito.when(mockedMerveille.getNomEn()).thenReturn("Rhodes Colossus");
    Mockito.when(mockedJoueur.getMerveille()).thenReturn(mockedMerveille);
    Mockito.when(mockedJoueur.getEtageMerveille()).thenReturn(2);
    assertEquals(2, partieManager.calculePuissanceMilitaire(partie, mockedJoueur));
  }

Plus besoin de créer le joueur et la merveille, les mocks simples suffisent pour ce test.

Publicités

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion /  Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion /  Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion /  Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion /  Changer )

w

Connexion à %s