Initial upload: iptv-android-tv-hermes
This commit is contained in:
+130
@@ -0,0 +1,130 @@
|
||||
# Stratégie de test — iMedia TV+
|
||||
|
||||
## Principes
|
||||
|
||||
- **TDD partout où c'est possible** : écrire le test avant l'implémentation
|
||||
- **Couverture cible** : > 70% sur les couches `data/` et `util/`
|
||||
- **Tests UI** : parcours critiques uniquement (login, lecture, favoris)
|
||||
- **Exécution locale** : tous les tests doivent passer avant chaque commit
|
||||
|
||||
## Stack de test
|
||||
|
||||
| Technologie | Usage |
|
||||
|-------------|-------|
|
||||
| JUnit 5 | Runner principal |
|
||||
| MockK | Mocking Kotlin (classes, objects, extensions) |
|
||||
| Turbine | Test des Flow (StateFlow, SharedFlow) |
|
||||
| Kotlinx Coroutines Test | `runTest`, `TestDispatcher` |
|
||||
| Compose UI Test | Test des écrans Compose TV |
|
||||
| Espresso | Complément pour interactions système |
|
||||
|
||||
## Tests unitaires
|
||||
|
||||
### data/repository/
|
||||
|
||||
| Fichier | Scénarios |
|
||||
|---------|-----------|
|
||||
| `AuthRepositoryTest.kt` | ✅ Réponse valide → `auth == "1"` → `Success` |
|
||||
| | ✅ Réponse valide → `auth == "0"` → `Error("Identifiants incorrects")` |
|
||||
| | ✅ Timeout → `Error("Le serveur ne répond pas")` |
|
||||
| | ✅ Socket error → `Error("Aucune connexion réseau")` |
|
||||
| `LiveRepositoryTest.kt` | ✅ Catégories chargées → liste triée FR/AR/autres |
|
||||
| | ✅ Chaînes filtrées par catégorie |
|
||||
| | ✅ Flux vide → liste vide (pas de crash) |
|
||||
| `EpgRepositoryTest.kt` | ✅ Cache valide (< 2min) → pas d'appel API |
|
||||
| | ✅ Cache expiré → appel API + mise à jour cache |
|
||||
| | ✅ Pas de cache → appel API + insertion |
|
||||
| | ✅ EPG vide → `Error("Aucun programme")` |
|
||||
| `FavoritesRepositoryTest.kt` | ✅ Ajout favori → liste contient l'ID |
|
||||
| | ✅ Suppression → liste ne contient plus l'ID |
|
||||
| | ✅ Persistance → données conservées après recreation du repo |
|
||||
| `SeriesRepositoryTest.kt` | ✅ Détail série retourne saisons + épisodes |
|
||||
| | ✅ Épisode sans titre → fallback "Épisode N" |
|
||||
|
||||
### data/storage/
|
||||
|
||||
| Fichier | Scénarios |
|
||||
|---------|-----------|
|
||||
| `SecureStorageTest.kt` | ✅ Valeur écrite = valeur lue |
|
||||
| | ✅ Données différentes après clair vs chiffré |
|
||||
| | ✅ Clear supprime toutes les données |
|
||||
| | ✅ Valeur inexistante → null safe |
|
||||
|
||||
### util/
|
||||
|
||||
| Fichier | Scénarios |
|
||||
|---------|-----------|
|
||||
| `CategorySortUtilsTest.kt` | ✅ Catégories FR en premier |
|
||||
| | ✅ Catégories AR ensuite |
|
||||
| | ✅ Catégories "Toutes" et "Favoris" toujours en haut |
|
||||
| | ✅ Autres en dernier |
|
||||
| | ✅ Ordre alphabétique à l'intérieur des groupes |
|
||||
| `XtreamUrlBuilderTest.kt` | ✅ URL Live correcte avec m3u8 |
|
||||
| | ✅ URL VOD avec extension dynamique |
|
||||
| | ✅ URL série avec épisode_id |
|
||||
| | ✅ URL Replay avec timestamp formaté |
|
||||
|
||||
## Tests d'intégration / UI
|
||||
|
||||
| Fichier | Parcours |
|
||||
|---------|----------|
|
||||
| `LoginScreenTest.kt` | ✅ Remplit les champs → bouton Connexion activé |
|
||||
| | ✅ Champs vides → bouton désactivé |
|
||||
| | ✅ Erreur réseau → message d'erreur visible |
|
||||
| | ✅ Connexion OK → navigation vers HomeScreen |
|
||||
| `HomeScreenTest.kt` | ✅ Catégories affichées au chargement |
|
||||
| | ✅ Changement de catégorie → nouvelles chaînes |
|
||||
| | ✅ Favori accessible avec télécommande (DPAD) |
|
||||
| | ✅ Recherche par nom fonctionne |
|
||||
| `PlayerScreenTest.kt` | ✅ Overlay visible → disparaît après 3s |
|
||||
| | ✅ Zapping gauche → chaîne précédente |
|
||||
| | ✅ Premier retour → overlay réapparaît |
|
||||
| | ✅ Deuxième retour → retour à HomeScreen |
|
||||
|
||||
## Exécution
|
||||
|
||||
```powershell
|
||||
# Tout
|
||||
.\gradlew.bat test connectedAndroidTest --no-daemon
|
||||
|
||||
# Tests unitaires uniquement
|
||||
.\gradlew.bat test --no-daemon
|
||||
|
||||
# Tests UI
|
||||
.\gradlew.bat connectedAndroidTest --no-daemon
|
||||
|
||||
# Filtre par classe
|
||||
.\gradlew.bat test --no-daemon --tests *AuthRepositoryTest*
|
||||
.\gradlew.bat connectedAndroidTest --no-daemon --tests *LoginScreenTest*
|
||||
|
||||
# Rapport de couverture
|
||||
.\gradlew.bat :app:createDebugCoverageReport --no-daemon
|
||||
# HTML → app/build/reports/coverage/debug/index.html
|
||||
```
|
||||
|
||||
## Convention d'écriture
|
||||
|
||||
```kotlin
|
||||
class AuthRepositoryTest {
|
||||
private val api = mockk<XtreamApi>()
|
||||
private val storage = mockk<SecureStorage>()
|
||||
private val repo = AuthRepository(api, storage)
|
||||
|
||||
@Test
|
||||
fun `login with valid credentials returns Success`() = runTest {
|
||||
// Given
|
||||
coEvery { api.authenticate(any(), any(), any()) } returns AuthResponse(
|
||||
userInfo = UserInfo(username = "test"),
|
||||
auth = "1",
|
||||
status = "Active"
|
||||
)
|
||||
|
||||
// When
|
||||
val result = repo.login("http://server", "user", "pass")
|
||||
|
||||
// Then
|
||||
assertTrue(result is UiState.Success)
|
||||
assertEquals("test", (result as UiState.Success).data.username)
|
||||
}
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user