GLO-4002 - Site du cours 2023

Temps estimé: 20 minutes

Exercices à propos des tests unitaires et des mocks

Question 1

Précédemment, on vous a parlé de la fragilité des tests, mais pour quelle raison il serait normal d'avoir à modifier des tests après les avoir écrits.

Lorsque le comportement demandé, c'est à dire la logique, change.

Question 2

Quelle mauvaise odeur cela présage-t-il que les tests d'une classe soient difficiles à écrire?

Si une classe est difficile à tester, cela peut vouloir dire que le code n'a pas été conçu de manière à être testable et ne respecte probablement pas les bonnes pratiques de conception OO. Il peut s'agir d'un signe que l'architecture du code devrait être revue.

Exemple:


public class ShoppingCartService {
  public void oneClickBuy(String sku, Integer quantity) {
    ShoppingCart cart = new ShoppingCart();

    Product product = Database.getSingleton().findProduct(sku);
    cart.addProduct(product, quantity);

    cart.checkout();
  }
}

Dans le cas présent, il y a une violation du SRP et OCP et l'utilisation d'une méthode statique (le singleton).

Question 3

Vrai ou Faux: Le cycle de vie des modifications d'un objet a rapport avec le choix de mettre un mock.

Vrai, si le cycle de vie d'une classe est le même que celui de la classe testée (quand une classe a des modifications, l'autre a aussi des changements), il est préférable de ne pas mocker la classe.

En effet, mettre un mock demande d'avoir une stabilité (une dépendance stable). Si les deux sont intimement liées alors la dépendance sera peu stable. Auquel cas les 2 classes risquent de changer + le mock.

En plus, il est possible que le résultat final de la classe A ne change pas laissant le test intact. Le mock au mileu brise alors la boîte noire et risque de faire briser le test qui n'aurait pas brisé sinon. Par contre, cela est vrai seulement si la dépendance n'est pas stable.

Question 4

Vrai ou faux: Une couverture de 100% permet d'avoir entièrement confiance dans les tests.

Faux, un coverage de 100% n'indique pas si les comportements sont réellement testés. Il est possible d'avoir un taux de coverage de 100%, mais que des bugs soient quand même présents dans le code.

Question 5

Quelles sont les raisons pour lesquelles il ne faudrait pas mocker une classe?

Entre autres, lorsqu'il n'y a pas de logique dans cette dernière (ex. value object, assembler), lorsque le code fait principalement appel à une librairie externe qui est déjà testée ou lorsque les deux classes sont intimement liées (cycle de vie de modification similaires).

Question 6

Est-ce un "smell" de mocker une classe concrète?

Astuce: prenez cette affirmation dans le sens inverse: si on décide de ne PAS mettre consciemment une abstraction, alors cela veut probablement dire de ne pas mettre de mock. Ou si vous sentez le besoin de mettre un mock, peut-être que cela remet en cause votre décision d'abstraire ou non.

Voir la réponse de Steve Freeman sur le sujet: http://www.mockobjects.com/2007/04/test-smell-mocking-concrete-classes.html

Nous recommandons la lecture du chapitre "20. Listening to the Tests", section "Mocking Concrete Classes", du livre "Growing Object-Oriented Software Guided by Tests". Disponible en ligne via la bibliothèque.

Question 7

Que pensez-vous de ce test?

@Test
public void shouldAssignNewCustomersToTheFirstTableAvailableWhenGreetingThem() {
    Customer customer = givenACustomer();

    restaurant.greet(customer);

    assertThat(restaurant.tables[0].customer).isSameAs(customer)
}

Le test sait maintenant que le restaurant possède des tables dans un Array (il connait l'implémentation). Si un jour on voulait changer pour une liste, ou une map, on est cuits!