Introduction
Tester du code dépendant du temps est notoirement difficile. Ce tutoriel vous enseignera des stratégies efficaces pour écrire des tests fiables pour du code lié aux horodatages.
Ce que Vous Apprendrez
- ✅ Pourquoi le test du temps est difficile
- ✅ Mocking du temps en JavaScript/Jest
- ✅ Freezegun en Python
- ✅ Test des transitions DST
- ✅ Test de multiples fuseaux horaires
- ✅ Meilleures pratiques
Pourquoi C'est Difficile
JAVASCRIPT1// Ce test peut échouer aléatoirement 2test('l\'événement expire après 1 heure', () => { 3 const evenement = creerEvenement(); 4 // ❌ Dépend du temps actuel 5 expect(evenement.expire()).toBe(false); 6});
Problèmes :
- Le temps actuel change constamment
- Le DST peut affecter les résultats
- Les tests peuvent échouer près de minuit
Mocking en JavaScript (Jest)
Fake Timers
JAVASCRIPT1describe('Expiration d\'événements', () => { 2 beforeEach(() => { 3 jest.useFakeTimers(); 4 }); 5 6 afterEach(() => { 7 jest.useRealTimers(); 8 }); 9 10 test('l\'événement expire après 1 heure', () => { 11 // Fixer le temps à une date spécifique 12 jest.setSystemTime(new Date('2024-01-15T10:00:00Z')); 13 14 const evenement = creerEvenement({ duree: 60 * 60 * 1000 }); 15 expect(evenement.expire()).toBe(false); 16 17 // Avancer le temps de 30 minutes 18 jest.advanceTimersByTime(30 * 60 * 1000); 19 expect(evenement.expire()).toBe(false); 20 21 // Avancer de 31 minutes de plus (total 61 min) 22 jest.advanceTimersByTime(31 * 60 * 1000); 23 expect(evenement.expire()).toBe(true); 24 }); 25});
Mock de Date.now()
JAVASCRIPT1test('horodatage de création', () => { 2 const maintenant = 1705312800000; // 2024-01-15T10:00:00Z 3 const espion = jest.spyOn(Date, 'now').mockReturnValue(maintenant); 4 5 const enregistrement = creerEnregistrement(); 6 expect(enregistrement.creeA).toBe(maintenant); 7 8 espion.mockRestore(); 9});
Freezegun en Python
Basique
PYTHON1from freezegun import freeze_time 2from datetime import datetime 3 4@freeze_time("2024-01-15 10:00:00") 5def test_horodatage_creation(): 6 enregistrement = creer_enregistrement() 7 8 assert enregistrement.cree_a == datetime(2024, 1, 15, 10, 0, 0) 9 10@freeze_time("2024-01-15 10:00:00") 11def test_expiration(): 12 evenement = creer_evenement(duree_secondes=3600) 13 14 assert not evenement.expire() 15 16 # Déplacer le temps en avant 17 with freeze_time("2024-01-15 11:01:00"): 18 assert evenement.expire()
Avec Fuseaux Horaires
PYTHON1from freezegun import freeze_time 2from datetime import datetime 3from zoneinfo import ZoneInfo 4 5@freeze_time("2024-01-15 10:00:00", tz_offset=-5) 6def test_avec_fuseau_horaire(): 7 utc = ZoneInfo('UTC') 8 ny = ZoneInfo('America/New_York') 9 10 maintenant_utc = datetime.now(utc) 11 maintenant_ny = datetime.now(ny) 12 13 assert maintenant_utc.hour == 15 # 10 AM UTC + offset simulé
Test du DST
JavaScript
JAVASCRIPT1describe('Transitions DST', () => { 2 test('Spring Forward - heure manquante', () => { 3 // 31 mars 2024, 2h00 n'existe pas à Paris 4 jest.setSystemTime(new Date('2024-03-31T00:30:00Z')); 5 6 const evenement = planifierEvenement('Europe/Paris', '02:30'); 7 8 // Doit ajuster automatiquement 9 expect(evenement.heureLocale).toBe('03:30'); 10 }); 11 12 test('Fall Back - heure dupliquée', () => { 13 // 27 octobre 2024, 2h30 se produit deux fois 14 jest.setSystemTime(new Date('2024-10-27T00:30:00Z')); 15 16 const evenement = planifierEvenement('Europe/Paris', '02:30'); 17 18 // Doit choisir la seconde occurrence (après le changement) 19 expect(evenement.offset).toBe('+01:00'); 20 }); 21});
Python
PYTHON1from freezegun import freeze_time 2from datetime import datetime 3from zoneinfo import ZoneInfo 4 5def test_spring_forward(): 6 """Test heure manquante pendant DST""" 7 paris = ZoneInfo('Europe/Paris') 8 9 # Juste avant le changement 10 with freeze_time("2024-03-31 00:59:00"): 11 avant = datetime.now(paris) 12 13 # Juste après le changement 14 with freeze_time("2024-03-31 03:01:00"): 15 apres = datetime.now(paris) 16 17 # Vérifier que l'offset a changé 18 assert avant.strftime('%z') == '+0100' 19 assert apres.strftime('%z') == '+0200'
Test de Multiples Fuseaux Horaires
PYTHON1import pytest 2from datetime import datetime 3from zoneinfo import ZoneInfo 4 5FUSEAUX_HORAIRES_TEST = [ 6 'UTC', 7 'America/New_York', 8 'Europe/Paris', 9 'Asia/Tokyo', 10 'Australia/Sydney', 11] 12 13@pytest.mark.parametrize('zone', FUSEAUX_HORAIRES_TEST) 14def test_conversion_fuseau_horaire(zone): 15 """Vérifie la conversion correcte dans tous les fuseaux""" 16 utc = ZoneInfo('UTC') 17 tz = ZoneInfo(zone) 18 19 # Créer horodatage en UTC 20 dt_utc = datetime(2024, 6, 15, 12, 0, 0, tzinfo=utc) 21 22 # Convertir en zone locale 23 dt_local = dt_utc.astimezone(tz) 24 25 # Vérifier qu'ils représentent le même instant 26 assert dt_utc.timestamp() == dt_local.timestamp()
Meilleures Pratiques
1. Isoler l'Obtention du Temps
JAVASCRIPT1// ❌ Difficile à tester 2function creerEvenement() { 3 return { 4 creeA: Date.now(), 5 // ... 6 }; 7} 8 9// ✅ Facile à tester 10function creerEvenement(obtenirTemps = Date.now) { 11 return { 12 creeA: obtenirTemps(), 13 // ... 14 }; 15}
2. Utiliser des Interfaces d'Horloge
PYTHON1# Interface d'horloge injectable 2class Horloge: 3 def maintenant(self): 4 return datetime.now(timezone.utc) 5 6class HorlogeFixe: 7 def __init__(self, temps_fixe): 8 self._temps = temps_fixe 9 10 def maintenant(self): 11 return self._temps 12 13# Dans les tests 14def test_avec_horloge_fixe(): 15 horloge = HorlogeFixe(datetime(2024, 1, 15, 10, 0, tzinfo=timezone.utc)) 16 service = MonService(horloge=horloge) 17 # ...
3. Tester les Cas Limites
PYTHON1DATES_LIMITES_TEST = [ 2 datetime(2024, 1, 1, 0, 0, 0), # Nouvel an 3 datetime(2024, 2, 29, 12, 0, 0), # Année bissextile 4 datetime(2024, 3, 31, 2, 30, 0), # Spring Forward 5 datetime(2024, 10, 27, 2, 30, 0), # Fall Back 6 datetime(2024, 12, 31, 23, 59, 59), # Fin d'année 7]
Résumé
- Utilisez fake timers en Jest pour contrôler le temps
- Utilisez freezegun en Python pour geler le temps
- Testez explicitement les transitions DST
- Testez avec multiples fuseaux horaires
- Injectez l'obtention du temps pour faciliter les tests
Essayez notre Convertisseur Unix Timestamp pour vérifier vos calculs !