Les dépendances
Nous avons un test très satisfaisant.
// Avant : le calendrier est vide
const initialCalendar = Calendar.of(accomodation)
expect(initialCalendar.count()).toBe(0)
// Réservation puis annulation
const bookings = await run(
Calendar.of(accomodation),
book(tenant1, stay)
cancel,
)
// Aucune réservation est acceptée.
const alteredCalendar = Calendar.of(accomodation)
expect(alteredCalendar.count()).toBe(0)
Mais un problème demeure : ou sont gérées les données représentatives de l'état du système ?
Le test débute par la construction du calendrier des réservations d'un hébergement :
const initialCalendar = Calendar.of(accomodation)
Mais de quel hébergement accomodation
parle-t-on ?
Given
Pour que notre réservation fonctionne, il nous faut des pré-requis : un hébergement accomodation
, un utilisateur tenant
souhaitant le louer.
Ces deux entités doivent exister a priori dans le système.
Deux solutions possibles :
- On augmente l'histoire pour raconter aussi la création de l'hébergement
Il était une fois un propriétaire voulant louer son hébergement. Un utilisateur qui prépare ses vacances s'inscrit surnotre plateforme et réalise une réservation.
// Inscription du propriétaire et création de l'hébergement sur la plateforme
const accomodation = await run(
signup({email:"fakehost@mail.com", pwd:"testpwd"}),
login("fakehost@mail.com", "testpwd"),
addAccomodation({name:"lovely house", address:"12 route de la plage, 50340 Sciotot"}),
);
// Inscription d'un utilisateur à la recherche d'un hébergement à louer
const tenant = await run(
signup({email:"faketenant@mail.com", pwd:"testpwd"}),
);
// Réalisation de la location
const bookings = await run(
Calendar.of(accomodation),
book(tenant1, stay)
);
Le test n'est plus spéciquement centré sur le cas d'usage de la réservation.
Il comporte plusieurs autres commandes signup
login
addAccomodation
nécessaires pour raconter toute l'histoire.
Il nous faudra coder toutes ces commandes pour faire passer le test.
C'est un test d'ensemble intéressant, pour valider le chemin "normal" d'utilisation de notre webapp. Mais il ne s'agit pas d'un test unitaire, qui ne teste qu'une seule commande.
- Les fixtures
Une autre solution consiste à peupler l'état du système avec des données.
Au lieu de partir d'un état vide (ni utilisateur, ni hébergement), on définit un état intial comportant au moins 1 utilisateur (ou plutôt 2 : un loueur et un vacancier) et 1 hébergement.
Repositories
Intéressons-nous à la lecture et l'écriture de données dans l'état du système.
Etablissons avec autorité ce qui sera le plus simple pour nous : une interface.
// On récupère l'hébergement déjà existant
const accomodation = await dependencies.findAccomodationById("accomodation-1")
// et le vacancier
const tenant = await dependencies.findUserByEmail("faketenant@mail.com")
// Réalisation de la location
const bookings = await run(
Calendar.of(accomodation),
book(tenant1, stay)
);
Voici un nouvel objet dependencies
qui comporte 2 méthodes permettant de lire les données.
Mais est-ce vraiment la reponsabilité de notre test d'aller chercher les données dont la commande a besoin ?
Non, la commande peut se débrouiller toute seule.
const app = new App(testDependencies())
// Réalisation de la location
const bookings = await app.run(
Calendar.of(accomodation),
book(tenant1, stay)
);
Injection de dépendances
Encore un nouvel objet app
!
Mais notre test est tellement plus simple.
Il se désintéresse de l'hébergement et de l'utilisateur initialement présent dans l'état.
Ces deux entités ont été déléguées dans un objet obtenu par l'appel à la fonction testDependencies()
.
Et notre commande book()
est désormais invoquée par app.run
qui va injecter la dépendance dont elle a besoin.
Inutile de préparer toutes les données nécessaires à notre commande, elle se débrouille. Il suffit de lui préciser les paramètres du séjour.
Quel serait notre test complet désormais ?
// Injection des dépendances
const app = new App(testDependencies())
// Réalisation de la location
await app.run(
book({
tenantId:"faketenant@mail.com",
accomodationId:"accomodation-1",
adults:2, children:3,
from : new Date("2024-06-02"),
to : new Date("2024-06-02"),
})
);
// Le calendrier comporte la réservation
const bookings = await app.dependencies.listBookingsForAccomodationId("accomodation-1")
expect(bookings).toHaveLength(1)