Cette base sépare volontairement les tests rapides JVM des tests Android instrumentés.
app/src/test)Ils couvrent les règles métier, les agrégations météo, le mapping réseau, les ViewModels, les widgets purs et les schedulers testables sans appareil. Le moteur d’évolution y vérifie notamment la sélection des snapshots locaux ~24/~48/~72 h, l’intersection des modèles comparables, les révisions, la détection des tendances et l’absence d’impact d’une erreur d’historisation sur la prévision principale. Ils ne doivent dépendre ni du réseau réel, ni de l’heure système non contrôlée, ni d’une base Android persistante.
app/src/androidTest)Ils couvrent ce qui nécessite Android :
MainActivity avec repositories Hilt factices ;Les parcours d’application n’utilisent jamais Open-Meteo. TestRepositoryModule remplace les repositories de production par des fakes déterministes. Les dates de fixtures sont calculées relativement au jour d’exécution puis figées pour tout le processus de test.
Sous Windows :
.\gradlew.bat testDebugUnitTest
.\gradlew.bat connectedDebugAndroidTest
.\gradlew.bat lintDebug
.\gradlew.bat assembleDebug
Validation complète :
.\gradlew.bat testDebugUnitTest connectedDebugAndroidTest lintDebug assembleDebug
Sous macOS/Linux, remplacer gradlew.bat par ./gradlew.
androidTest.Avant une release, exécuter au minimum la suite sur une locale française et une locale anglaise, ainsi que sur un appareil physique si possible.
setContent une seule fois.testTag, un rôle sémantique ou une ressource localisée, jamais une chaîne française arbitraire quand elle peut varier.Pour obtenir davantage de détails :
.\gradlew.bat connectedDebugAndroidTest --stacktrace --info
Les rapports sont générés dans :
app/build/reports/tests/testDebugUnitTest/app/build/reports/androidTests/connected/app/build/reports/lint-results-debug.htmlLe résumé quotidien n’utilise plus WorkManager.setInitialDelay() comme
horloge. Une alarme RTC inexacte (AlarmManager.setAndAllowWhileIdle) réveille
l’application autour de l’heure choisie puis déclenche un work immédiat portant
le tag meteocompare_notifications. Les alertes divergence/révision restent
périodiques, avec un contrôle immédiat lors d’une modification explicite des
réglages.
Logs utiles :
adb logcat -s MeteoCompare/Notif WM-WorkerWrapper WM-Processor WM-SystemJobService
adb shell dumpsys alarm | findstr /I "meteocompare WEATHER_NOTIFICATION_DAILY_SUMMARY"
adb shell dumpsys jobscheduler | findstr /I "meteocompare notifications"
Recette de non-régression du résumé quotidien :
Daily alarm scheduled for ..., puis
Daily summary alarm fired ..., Starting notification cycle: DAILY_SUMMARY
et enfin Posted daily|... ;Test Doze recommandé :
adb shell dumpsys deviceidle force-idle
# Laisser passer l'heure choisie, sans ouvrir l'application.
adb shell dumpsys deviceidle unforce
adb shell input keyevent KEYCODE_WAKEUP
setAndAllowWhileIdle() est volontairement inexact : Android ne doit jamais
notifier avant l’heure choisie, mais peut décaler l’alarme selon ses politiques
d’économie d’énergie. Le critère de régression essentiel est que la notification
ne dépende plus de la réouverture de l’application.
Pour les alertes :
Le travail périodique porte le tag meteocompare_widget et le nom unique
meteocompare_widget_refresh. Pour diagnostiquer un téléphone où le launcher
semble conserver une ancienne vue :
adb logcat -s MeteoCompare/Widget WM-WorkerWrapper WM-Processor
adb shell dumpsys jobscheduler | findstr /I "meteocompare widget_refresh"
Test de reprise après veille profonde :
adb shell dumpsys deviceidle force-idle
# Attendre, puis sortir du mode idle
adb shell dumpsys deviceidle unforce
adb shell input keyevent KEYCODE_WAKEUP
Points à vérifier :
ENQUEUED entre deux exécutions ;force-stop manuel bloque volontairement tous les composants Android
jusqu’à la prochaine ouverture de l’application : ce cas ne peut pas être
contourné par WorkManager ou par un receiver.Avant toute release construite à partir de l’audit R9 :
.\gradlew.bat clean testDebugUnitTest testReleaseUnitTest lintDebug assembleDebug assembleRelease
.\gradlew.bat connectedDebugAndroidTest
Points manuels ciblés à vérifier en plus de la suite automatisée :
Les tests JVM utilisent MockK 1.14.11. Son agent déclare Byte Buddy 1.18.2 transitivement ; MeteoCompare force byte-buddy et byte-buddy-agent en 1.18.9 dans le classpath test afin d’utiliser le chemin d’injection compatible JDK 25 et d’éviter l’appel terminalement déprécié à sun.misc.Unsafe::objectFieldOffset.
Pour vérifier la résolution réellement utilisée :
.\gradlew.bat :app:dependencyInsight --dependency byte-buddy --configuration testReleaseRuntimeClasspath
.\gradlew.bat :app:dependencyInsight --dependency byte-buddy-agent --configuration testReleaseRuntimeClasspath
La version sélectionnée doit être 1.18.9.
Le libellé de condition ne doit plus sur-représenter « Couvert » lorsque les modèles secs sont répartis entre CLEAR, MAINLY_CLEAR, PARTLY_CLOUDY et OVERCAST.
Tests automatiques ciblés :
WeatherConditionConsensusTest : regroupement du ciel sec, conservation du vote brut pour la convergence, priorité aux phénomènes significatifs et tie-break prudent sec/pluie ;WeatherConditionTest : seuils de nébulosité <20 / <45 / <85 / ≥85 % ;ForecastAggregatesTest : propagation du consensus hiérarchique dans le mini-forecast widget 12 h ;WeatherScenarioBuilderTest : un ciel sec à 82 % reste VARIABLE_SKY, pas OVERCAST.Recette manuelle recommandée : choisir une ville où plusieurs modèles oscillent entre codes WMO 1/2/3, comparer le pourcentage de nébulosité et l’icône affichée sur Home, Détails et widgets. Entre 45 et 84 % de nébulosité centrale, un ciel sec doit rester « Partiellement nuageux » ; pluie/neige/brouillard/orage doivent continuer à primer lorsqu’ils gagnent le vote catégoriel familial.
R11 remplace le regroupement ponctuel DRY_SKY de R10 par un arbre sémantique complet. Le test doit vérifier la décision à chaque niveau, pas seulement le ciel sec.
Arbre de référence :
ROOT
├─ NON_PRECIPITATION
│ ├─ SKY → CLEAR / MAINLY_CLEAR / PARTLY_CLOUDY / OVERCAST
│ └─ FOG
└─ PRECIPITATION
├─ LIQUID → DRIZZLE / RAIN_SHOWERS / RAIN
├─ FROZEN → SNOW_SHOWERS / SNOW
├─ FREEZING_RAIN
└─ THUNDERSTORM
Tests ciblés dans WeatherConditionConsensusTest :
DRIZZLE + RAIN_SHOWERS + RAIN consolidés avant comparaison à NON_PRECIPITATION ;SNOW + SNOW_SHOWERS consolidés avant comparaison à la pluie liquide ;SKY + FOG consolidés au niveau NON_PRECIPITATION ;LIQUID est plus soutenue ;PRECIPITATION / NON_PRECIPITATION toujours prudente vers la précipitation ;UNKNOWN sont couvertes par exactement une feuille de l’arbre ;Recette manuelle : vérifier sur Home, Détails, widgets et Engine Comparison qu’une majorité sémantique ne se fragmente plus entre sous-types voisins, tout en contrôlant que le pourcentage de convergence reste inchangé par rapport aux codes WMO bruts.
./gradlew :app:testDebugUnitTest --tests 'com.meteocompare.app.ui.citylist.CityCardExpansionTest'
./gradlew :app:connectedDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=com.meteocompare.app.ui.citylist.CityCardExpansionUiTest
AdaptiveNavigationContentTest et
CityListContentTest vérifient le focus de la ville récemment ajoutée,
l’état sélectionné et le volet détails.À vérifier également manuellement sur un petit écran et en mode sombre : largeurs très étroites, longues dénominations de villes, lecteur d’écran, unités impériales et actions contextuelles après dépliage.