Unité Android Kotlin CoroutineTest

Mitch

J'ai un broadcastReceiver qui démarre une coroutine et j'essaye de tester cela unitaire ...

L'émission:

class AlarmBroadcastReceiver: BroadcastReceiver() {

override fun onReceive(context: Context?, intent: Intent?) {
    Timber.d("Starting alarm from broadcast receiver")
    //inject(context) Don't worry about this, it's mocked out

    GlobalScope.launch {
        val alarm = getAlarm(intent)
        startTriggerActivity(alarm, context)
    }
}

private suspend fun getAlarm(intent: Intent?): Alarm {
    val alarmId = intent?.getIntExtra(AndroidAlarmService.ALARM_ID_KEY, -1)
    if (alarmId == null || alarmId < 0) {
        throw RuntimeException("Cannot start an alarm with an invalid ID.")
    }

    return withContext(Dispatchers.IO) {
        alarmRepository.getAlarmById(alarmId)
    }
}

Et voici le test:

@Test
fun onReceive_ValidAlarm_StartsTriggerActivity() {
    val alarm = Alarm().apply { id = 100 }
    val intent: Intent = mock {
        on { getIntExtra(any(), any()) }.thenReturn(alarm.id)
    }

    whenever(alarmRepository.getAlarmById(alarm.id)).thenReturn(alarm)

    alarmBroadcastReceiver.onReceive(context, intent)

    verify(context).startActivity(any())
}

Ce qui se passe, c'est que la fonction que je vérifie n'est jamais appelée. Le test se termine avant le retour de la coroutine ... Je sais que GlobalScopec'est mauvais à utiliser, mais je ne sais pas comment faire autrement.

EDIT 1: Si je mets un délai avant le verify, cela semble fonctionner, car cela laisse le temps à la coroutine de se terminer et de revenir, cependant, je ne veux pas avoir de test reposant sur le retard / sommeil ... je pense que la solution est d'introduire correctement une portée au lieu de l'utiliser GlobalScopeet de la contrôler dans le test. Hélas, je n'ai aucune idée de la convention de déclaration des portées coroutines.

Rodrigo Queiroz

Je vois, vous devrez utiliser un Unconfinedrépartiteur:

val Unconfined: CoroutineDispatcher (source)

Un répartiteur de coroutine qui n'est confiné à aucun thread spécifique. Il exécute la continuation initiale d'une coroutine dans la trame d'appel courante et laisse la coroutine reprendre dans n'importe quel thread utilisé par la fonction de suspension correspondante, sans imposer de politique de threading spécifique. Les coroutines imbriquées lancées dans ce répartiteur forment une boucle d'événements pour éviter les débordements de pile.

Échantillon de documentation:

withContext(Dispatcher.Unconfined) {
   println(1)
   withContext(Dispatcher.Unconfined) { // Nested unconfined
       println(2)
   }
   println(3)
}
println("Done")

Pour mes tests ViewModel, je passe un contexte coroutine au constructeur ViewModel afin que je puisse basculer entre Unconfinedet d'autres répartiteurs, par exemple Dispatchers.Mainet Dispatchers.IO.

Contexte Coroutine pour les tests:

@ExperimentalCoroutinesApi
class TestContextProvider : CoroutineContextProvider() {
    override val Main: CoroutineContext = Unconfined
    override val IO: CoroutineContext = Unconfined
}

Contexte Coroutine pour l'implémentation actuelle de ViewModel:

open class CoroutineContextProvider {
    open val Main: CoroutineContext by lazy { Dispatchers.Main }
    open val IO: CoroutineContext by lazy { Dispatchers.IO }
}

VoirModèle:

@OpenForTesting
class SampleViewModel @Inject constructor(
        val coroutineContextProvider: CoroutineContextProvider
) : ViewModel(), CoroutineScope {

    private val job = Job()

    override val coroutineContext: CoroutineContext = job + coroutineContextProvider.Main
    override fun onCleared() = job.cancel()

    fun fetchData() {
        launch {
            val response = withContext(coroutineContextProvider.IO) {
                repository.fetchData()
            }
        }
    }

}

Mettre à jour

À partir de la version coroutine-core, 1.2.1vous pouvez utiliser runBlockingTest:

Dépendances:

def coroutines_version = "1.2.1"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version"

par exemple:

@Test
fun `sendViewState() sends displayError`(): Unit = runBlockingTest {
    Dispatchers.setMain(Dispatchers.Unconfined)
    val apiResponse = ApiResponse.success(data)
    whenever(repository.fetchData()).thenReturn(apiResponse) 
    viewModel.viewState.observeForever(observer)
    viewModel.processData()
    verify(observer).onChanged(expectedViewStateSubmitError)
}

Cet article est collecté sur Internet, veuillez indiquer la source lors de la réimpression.

En cas d'infraction, veuillez [email protected] Supprimer.

modifier le
0

laisse moi dire quelques mots

0commentaires
connexionAprès avoir participé à la revue

Articles connexes

TOP liste

  1. 1

    Comment changer le navigateur par défaut en Microsoft Edge pour Jupyter Notebook sous Windows 10 ?

  2. 2

    Enregistrer le chemin de l'image de la galerie vers la base de données de la salle et l'afficher dans la liste des recycleurs

  3. 3

    Microsoft.WebApplication.targets

  4. 4

    knn classification 10 plis de l'outil et du tri

  5. 5

    Quelle est la relation entre le modèle et le tableau ? C'est compliqué

  6. 6

    Créer un système Buzzer à l'aide de python

  7. 7

    Fonction de puissance en Java

  8. 8

    opérations en virgule flottante dans go

  9. 9

    Comment définir la couleur de l'intersection dans un diagramme de Venn?

  10. 10

    Spring @RequestParam DateTime format comme ISO 8601 Date Heure facultative

  11. 11

    comment supprimer "compte de connexion google" à des fins de développement - actions sur google

  12. 12

    AutoMapper.Collection.EFCore - Erreur générée lors de la configuration

  13. 13

    Je continue à obtenir l'objet 'WSGIRequest' n'a pas d'attribut 'Get' sur django

  14. 14

    Comment remplir les valeurs manquantes avec plusieurs colonnes dans R

  15. 15

    Comment puis-je ajouter un UIView sous mon contrôleur de barre d'onglets par programme?

  16. 16

    Yat-il un référentiel maven application Java à démarrer rapidement 11

  17. 17

    Comment rechercher des éléments dans une ArrayList? - Java

  18. 18

    Comment utiliser HttpClient avec TOUT cert ssl, quelle que soit la « mauvaise » est

  19. 19

    Comment créer un bot à compte à rebours dans Discord en utilisant Python

  20. 20

    Sélectionnez le bouton radio sur la saisie de texte

  21. 21

    Placez le modeBar en haut au centre à l'aide de plotly.js

chaudétiquette

Archive