Files

4.5 KiB

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

# 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

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)
    }
}