Quiz 2018

—-> On a réutilisé quelques questions dans 2019 —-> La question sur UTEST manuelle serait pertinente

Consignes

Question 1 — Polymorphisme

Considérez le code suivant:

public class Employe {
	//...
	public void payer(Periode periode) {
		Montant montant;
		if(this.tauxHoraire == 0) {
			montant = this.calculerSalaireAnnuel(periode);
		} else {
			montant = this.calculerSalaireHoraire(periode);
		}
		//...
	}
	//...
}

public class Contractuel {
	//...
	public void payer(Periode periode) {
		Montant montant = travaux.stream().reduce(new Montant(0),
												  (s, t) -> s.plus(t.getTotal());
		//...
	}
	//...
}

public class PaiementCommande {
	//...
	public void execute() {
		tousEmployes.forEach(employe -> employe.payer(periode));
		tousContractuels.forEach(contractuel -> contractuel.payer(periode));
	}
}

Le code présente un ou des problèmes d’abstraction. Quelle serait alors la meilleure solution:

  1. Une classe abstraite Paie

     public abstract class Paie { ... }
     public class Employe extends Paie { ... }
     public class Contractuel extends Paie { ... }
    
  2. Une interface Employe

     public interface Employe { ... }
     public class EmployeSalaireHoraire implements Employe { ... }
     public class EmployeSalaireAnnuel implements Employe { ... }
     public class Contractuel implements Employe { ... }
    
  3. Une classe abstraite Employe

     public abstract class Employe { ... }
     public class EmployeSalaireHoraire extends Employe { ... }
     public class EmployeSalaireAnnuel extends Employe { ... }
     public class Contractuel extends Employe { ... }
    
  4. Une classe concrète Employe dont les contractuels sont une variante (sous-classe)

     public class Employe { ... }
     public class Contractuel extends Employe { ... }
    
  5. Une interface Payable implémentée par tous

     public interface Payable { ... }
     public class EmployeSalaireHoraire implements Payable { ... }
     public class EmployeSalaireAnnuel implements Payable { ... }
     public class Contractuel implements Payable { ... }
    
  6. Deux groupements distincts pour les Employe (regroupés) et les Contractuel

     public interface Employe { ... }
     public class EmployeSalaireHoraire implements Employe { ... }
     public class EmployeSalaireAnnuel implements Employe { ... }
        
     public interface Contractuel { ... }
     public class ContractuelImpt implements Contractuel {...}
    

R: 5

Question 2 — Abstraction

Considérez le code suivant:

public class GrilleHoraire {
	private Map<Horaire, EvenementCaseHoraire> contenuAgenda;
	...
}

public class EvenementCaseHoraire {
	public void confirmer() {...}
	public void rendrePrive() {...}
	public void ecrireAuxParticipants(String message) {...}
	...
}

Certains pourraient se demander s’il ne serait pas mieux de rendre EvenementCaseHoraire abstrait (ex.: public interface EvenementCaseHoraire utilisé par GrilleHoraire) dans ce contexte d’affaires. Qu’en pensez-vous?

  1. Oui, c’est une bonne idée pour faciliter les tests
  2. Oui, c’est une bonne idée pour inverser la dépendance (EvenementCaseHoraire devient un “plugin”)
  3. Non, car EvenementCaseHoraire n’a pas de données.
  4. Non, car EvenementCaseHoraire et GrilleHoraire risquent de changer pour les mêmes raisons et il y a un fort risque que l’abstraction doive changer souvent.
  5. Oui, pour améliorer la cohésion

R: 4

Question 3 — Réutilisation

Considérez le code suivant:

public class RappelRendezVous {
	public void marquerLu() { this.lu = true; }
	...
}

public class EvenementChangementHoraire {
	public void marquerLu() { this.lu = true; }
}

public class NouveauMessageCourriel {
	public void marquerLu() { this.lu = true; }
}

Ces différents événements s’affichent sous la forme de notifications dans un centre de notifications de l’application. Ce centre de notifications permet de marquer la notification comme lue si cette notification le supporte.

Votre collègue vous propose alors de créer une classe abstraite MarquableLu:

public abstract class MarquableLu {
	public void marquerLu() { this.lu = true; }
}

En supposant que c’est une bonne idée, quel pourrait être un argument valable?

  1. Oui, car il y a du code identique (dupliqué)
  2. Oui, car le centre de notifications n’a pas besoin de connaître le type de notification mais uniquement si celle-ci peut être marquée comme lue.
  3. Oui car ce sont toutes des notifications.

R: 2

Question 4 — Tell don’t Ask

Considérez le code suivant:

public class TableauResumeUI {
    private UIWidget moyenneWidget = ...;
    private UIWidget valeurCouranteWidget = ...;
    
	public void afficher(Action action) {
		afficherValeurCourante(action);
		afficherMoyenne(action);
	}

	private void afficherValeurCourante(Action action) {
		valeurCouranteWidget.setText( action.getValeurCourante().toString() );
	}

	private afficherMoyenne(Action action) {
		List<Integer> valeurs = action.getHistorique();
		Integer moyenne = valeurs.stream().average();
		moyenneWidget.setText( moyenne.toString() );
	}
}

Quelle affirmation est VRAI:

  1. Il y a un respect de la loi de Demeter dans la méthode afficherValeurCourante
  2. Il y a un respect de la loi de Demeter dans la méthode afficherMoyenne
  3. La violation du Tell don’t Ask dans la méthode afficherValeurCourante n’est pas très grave et la complexité induite pour la corriger ne vaut pas la peine.
  4. La violation du Tell don’t Ask dans la méthode afficherMoyenne n’est pas très grave et la complexité induite pour la corriger ne vaut pas la peine.

R: 3

Question 5 — Tests unitaires

Voici un bout de code:

public class Passager {
	private int age;
	private double prix;

	public Passager(int age, double prix) {
		this.age = age;
		this.prix = prix;
	}

	public double calculerPrix() {
		if(age < 12) { return prix * 0.8; }
		return prix;
    }
	...
}

Et voici les tests unitaires correspondants

@Test
public void testConstructeur {
	Passager p = new Passager(1, 2.0);
	assertNotNull(p);
}

@Test
public void testAssignation {
	Passager p = new Passager(50, 2.0);
	assertEquals(50, p.getAge());
	assertEquals(2.0, p.getPrix());
}

@Test
public void enfant_quandCalculerPrix_devraitAppliquerRabais() {
	Passager p = new Passager(1, 2.0);
	double prixCalcule = p.calculerPrix();
	assertEquals(2.0 * 0.8, prixCalcule);
}

@Test
public void nePasAppliquerDeRabaisSurUnAdulte() {
	Passager p = new Passager(13, 2.0);
	double prixCalcule = p.calculerPrix();
	assertEquals(2.0, prixCalcule);
}

Quelle affirmation est FAUSSE:

  1. Il aurait été préférable d’utiliser des constantes plutôt que des valeurs magiques
  2. Il y a de la duplication dans ce code (les tests)
  3. nePasAppliquerDeRabaisSurUnAdulte peut être considéré comme un BON nom de test
  4. enfant_quandCalculerPrix_DevraitAppliquerRabais peut être considéré comme un BON nom de test
  5. Le code a été produit en utilisant le TDD
  6. Le test testConstructeur ne peut pas échouer
  7. Le test testAssignation n’est pas nécessaire et ne fait qu’ajouter du bruit

R: 5

Question 6 (formative) — Mocks

RAPPEL: Cette question est formative (n’est pas notée) mais est un type de question généralement posée à l’examen.

Note: Cette question combine à la fois vos apprentissages sur les tests unitaires mais aussi les concepts d’orientation objet. Nous sommes conscients que vous n’avez pas encore pratiqué les Mocks mais normalement avec les concepts OO, vous devriez pouvoir isoler une classe sans utiliser un outil particulier.

Voici une classe que l’on veut tester unitairement:

public class Produit {
    public Produit(String nom, double prix) {
        this.prixUnitaire = prix;
        this.nom = nom;
    }
    
	public void facturerSur(Facture facture) {
        CalculateurRabais calculateurRabais = new CalculateurRabais();

        double montant = prixUnitaire;
        if(calculateurRabais.taux() > 0) {
            montant = montant * calculateurRabais.taux();
        }
        
	    facture.inscrireArticle(nom, montant)
	}
}

public class CalculateurRabais {
    public double taux() { return 0.23; }
}

Sauf que cette classe n’est pas testable unitairement.

(1) Pourquoi ?

Sur une feuille blanche, vous devez:

(2) Réusiner (modifier) la classe Produit pour la rendre facilement testable tout en respectant les bonnes pratiques architecturales.

(3) Écrire les tests unitaires pour la méthode Produit::facturerSur (sur votre feuille) en utilisant des Mocks. Mais vous devez faire les Mocks à la “main” sans utiliser de framework comme Mockito.

Indice: Nous n’avons pas vu en classe comment faire des Mocks à la main. Mais avec la théorie du dernier cours combinée avec les cours sur l’orientation objet, vous avez tous les outils pour trouver l’astuce!

R: https://github.com/GLO4002UL/officiel-quiz-2018