<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Mohit Sarveiya on Medium]]></title>
        <description><![CDATA[Stories by Mohit Sarveiya on Medium]]></description>
        <link>https://medium.com/@heyitsmohit?source=rss-9057ae5f9de4------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/2*UHyJsHPfGa2EYgIhNvqbMg.jpeg</url>
            <title>Stories by Mohit Sarveiya on Medium</title>
            <link>https://medium.com/@heyitsmohit?source=rss-9057ae5f9de4------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 00:09:31 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@heyitsmohit/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Writing Kotlin Compiler Plugin with Arrow Meta]]></title>
            <link>https://medium.com/@heyitsmohit/writing-kotlin-compiler-plugin-with-arrow-meta-cf7b3689aa3e?source=rss-9057ae5f9de4------2</link>
            <guid isPermaLink="false">https://medium.com/p/cf7b3689aa3e</guid>
            <category><![CDATA[kotlin]]></category>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[kotlin-beginners]]></category>
            <category><![CDATA[compilers]]></category>
            <dc:creator><![CDATA[Mohit Sarveiya]]></dc:creator>
            <pubDate>Wed, 08 Apr 2020 13:28:57 GMT</pubDate>
            <atom:updated>2020-04-08T20:25:42.900Z</atom:updated>
            <content:encoded><![CDATA[<h3>Writing a Kotlin Compiler Plugin with Arrow Meta</h3><p><em>Follow me on Twitter</em><strong><em>: </em></strong><a href="https://twitter.com/heyitsmohit">https://twitter.com/heyitsmohit</a></p><p>Writing a Kotlin Compiler plugin is an uncharted area. The API is undocumented thus far. You may not know where to start. Enter <a href="https://meta.arrow-kt.io/">Arrow Meta</a>. It is a library that provides a functional API to write compiler plugins. In this article, I will show you how to write and test a simple compiler plugin with Arrow Meta.</p><p>Three years ago, a friend of mine Kevin Most gave a talk at Kotlin Conf on <a href="https://www.youtube.com/watch?v=w-GMlaziIyo">writing compiler plugins</a>. He demonstrated the process with an example plugin <a href="https://github.com/kevinmost/debuglog">DebugLog</a>. I worked on writing an Arrow Meta implementation of this plugin <a href="https://github.com/msya/debuglog-arrow-meta">debuglog-meta-arrow</a>. I’ll show you how I wrote it and introduce the API provided by Arrow Meta.</p><p>Before we begin, let’s look at an overview of how the Kotlin compiler works as Arrow Meta supplements it.</p><h3><strong>Kotlin Compiler</strong></h3><p>As with any compiler, the purpose is to convert your Kotlin code to something that can be executed. From a higher-level perspective, the compiler is divided into two sections — frontend and backend. The front-end performs lexical and grammatical analysis. This produces what is called an intermediate representation that typically takes the form of a tree. An <a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree">Abstract Syntax Tree</a> (AST) to be precise. Let’s look at an overview of the steps taken in these sections.</p><p><strong>Compilation</strong></p><p>Your code goes through a sequence of steps to compile. Below is a diagram of the process.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*r0O52_OF7iA4LrwdWNLO6g.png" /></figure><p><strong>Code</strong></p><p>Code is really just strings that we input into our editors. The editor that we primarily use, Intellij IDEA is built on top of the I<a href="https://github.com/JetBrains/intellij-community">ntellij Community</a> platform. This platform provides reusable UI components for IDEs and a way to hookup a custom grammar for a language, it also has grammar validation, etc. The Kotlin Compiler utilizes this platform to provides Kotlin specific configurations for the IDE. For example, the “Show Kotlin bytecode” option is shown by tapping into the <a href="https://github.com/JetBrains/kotlin/blob/c338fdd677e5228f6add319c4e3946150bbc6824/idea/idea-jvm/src/org/jetbrains/kotlin/idea/actions/ShowKotlinBytecodeAction.kt#L29">Actions API</a> provided by Intellij platform. This is hooked into the decompiler of Kotlin.</p><p><strong>Parsing</strong></p><p>Your code is converted from text to a tree-like structure called the <a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree">Abstract Syntax Tree</a>. This is actually not Kotlin specific. All compilers will transform your code into an AST for any other language. Each node in the AST represents a part of your code. For example, there will be a node for your imports, classes, functions, generic, etc.</p><p><strong>Analysis &amp; Resolve</strong></p><p>In this phase of the compilation process, the AST is given type information and actual type checking is performed. Every language has a grammar. This is Kotlin’s <a href="https://kotlin.github.io/kotlin-spec/#grammar">grammar</a> specification. Your code is parsed against the grammar to validate its correctness. In this phase, it will also type check your program.</p><p><strong>Code Generation</strong></p><p>The AST is given to the backend of the compiler. With the introduction of intermediate representation, the back-end can now target different platforms. These platforms could be JS, JVM, native.</p><p>All compilers have a very similar process. This is a very high-level overview of it. Arrow Meta allows you to hook into each step and provide your own custom implementation. The GIF below made by the Arrow team demonstrates this much better.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*bJy_47pfRW1TFKZIh6vyBA.gif" /><figcaption><a href="https://meta.arrow-kt.io/">https://meta.arrow-kt.io/</a></figcaption></figure><h3>Use Case</h3><p>Let’s look at how to write a plugin that mutates the AST and adds logging information. Assume we have a method that performs some operation and returns the result.</p><pre>fun prime(n: Int): Long = listOf(1L,2L,3L).take(n).last()</pre><p>We want to be able to log how long this function takes to execute. We have a program that has a lot of functions. We could use an annotation DebugLog to specify logging for a specific function.</p><pre><strong>annotation</strong> class DebugLog</pre><pre><strong>@DebugLog</strong><br>fun prime(n: Int): Long = listOf(1L,2L,3L).take(n).last()</pre><p>Our goal is to transform this function to add logging for how long it takes the function to execute. After transforming our function, it will look like this:</p><pre>fun prime(n: Int): Long {<br><strong>  println(“-&gt; prime(n=$n)”)</strong><br><strong>  val startTime = System.currentTimeMillis()</strong><br>  val result = listOf(1L,2L,3L).take(n).last()<br><strong>  val timeToRun = System.currentTimeMillis() — startTime</strong><br><strong>  println(“&lt;- prime[ran in $timeToRun ms]”)</strong><br>  return result<br>}</pre><p>As you can see above, we want to add logging of the parameter sent to the function, perform a time calculation and print it. How do we accomplish this with Arrow Meta?</p><p><strong>Modules</strong></p><p>We need to setup Gradle modules for our meta plugin. I will create two modules — create-plugin and use-plugin in our project.</p><p><strong>Create-Plugin</strong></p><p>This module will contain the main logic for the plugin. Its external dependencies will be:</p><ul><li>Kotlin Embeddable Compiler</li><li>Arrow Meta Compiler Plugin</li><li>Shadow Jar library</li></ul><p>Please take look at the build scripts in the project. I want to point out the main points of the configuration.</p><pre>plugins {<br>   id “org.jetbrains.kotlin.jvm”<br>   id “com.github.johnrengelman.shadow”<br>}</pre><pre>dependencies {<br>   compileOnly “org.jetbrains.kotlin:<br>                     kotlin-stdlib:$KOTLIN_VERSION”</pre><pre>   compileOnly “org.jetbrains.kotlin:<br>                     kotlin-compiler-embeddable:$KOTLIN_VERSION”</pre><pre>   compileOnly “com.github.arrow-kt.arrow-meta:<br>                     compiler-plugin:-SNAPSHOT”</pre><pre>}</pre><pre>shadowJar {<br>    configurations = [project.configurations.compileOnly]<br>    dependencies {<br>       exclude(“org.jetbrains.kotlin:kotlin-stdlib”)<br>       exclude(“org.jetbrains.kotlin:kotlin-compiler-embeddable”)<br>    }<br>}</pre><p>In my plugin, I’m using <a href="https://jitpack.io/">JitPack</a> to get the latest snapshot of Arrow Meta.</p><p><strong>Use-Plugin</strong></p><p>This module shows how to use the plugin in an example. The create-plugin module creates a jar that is included in freeCompilerArgs . This module will also contain the tests for our plugin. Here is the main configuration from the build script.</p><pre>compileKotlin {<br>   kotlinOptions {<br>      jvmTarget = “$JVM_TARGET_VERSION”<br>      <strong>freeCompilerArgs</strong> = [<br>           “-Xplugin=${project.rootDir}/create<br>                 plugin/build/libs/<strong>create-plugin-all.jar</strong>”]<br>     }<br>}</pre><p>For testing, I’m including the test plugin that provides testing utilities. With Jitpack, it’s easier to pull a submodule from the library.</p><pre>testImplementation <br>        ‘com.github.arrow-kt.arrow-meta:testing-plugin:-SNAPSHOT’</pre><p>If you want to look at this scaffolding in detail, you could check out my plugin.</p><p><strong>Compiler Plugin Entry Point</strong></p><p>The main entry point for the plugin needs to specify a list of extension phases. The extension phases are our hooks into the compiler we are specifying to perform code gen, type definition, etc.</p><pre>class DebugLogMetaPlugin : <strong>Meta</strong> {</pre><pre>    @ExperimentalContracts<br>    override fun intercept(ctx: CompilerContext): List&lt;Plugin&gt; =<br>        <em>listOf</em>(<br>            <strong><em>debugLog</em></strong><em><br>        </em>)<br>}</pre><p>In order to define the entry point for our plugin, we need to extend the Meta class and override the intercept method. We will return from this method a list of typePlugin . The debugLog item in the list is our Plugin where we have defined how to perform our desired transformation. Let’s see how the transformation is connected.</p><p><strong>Compiler Plugin</strong></p><pre>val Meta.<em>debugLog</em>: <strong>Plugin</strong><br> get() =<br>   <strong>&quot;DebugLog&quot;</strong> {<strong><br>     meta</strong>(<br>       <em>namedFunction</em>({<strong> </strong><em>validateFunction</em>() }) {<strong> </strong>c: KtNamedFunction -&gt;<strong><br>          </strong>Transform.replace(<br>            replacing = c,<br>            newDeclaration = <em>replace</em>(c).<em>function<br>          </em>)<br>        <strong>}<br>      </strong>)<br>    }</pre><p>Above is a plugin defined as an extension property. A <a href="https://github.com/arrow-kt/arrow-meta/blob/master/compiler-plugin/src/main/kotlin/arrow/meta/Meta.kt#L40">Plugin</a> is a data class consisting of two fields.</p><pre>data class Plugin(  <br>    val name: String,  <br>    val meta: CompilerContext.() -&gt; List&lt;ExtensionPhase&gt;<br>)</pre><p>Source: <a href="https://github.com/arrow-kt/arrow-meta/blob/master/compiler-plugin/src/main/kotlin/arrow/meta/Meta.kt#L40">Meta.kt</a></p><p>The first field specifies the name of our plugin which is “DebugLog”. The second field is a lambda block whose return type is a list of extension phases. We would like to intercept the compilation step where the compiler generates the AST. We need to search the AST for a function that has the DebugLog annotation. Arrow Meta provides an extension on the Meta type that allows you to parse any function defined in the code.</p><pre>fun Meta.<strong>namedFunction</strong>(<br>  <strong>match</strong>: KtNamedFunction.() -&gt; Boolean,<br>  <strong>map</strong>: NamedFunction.(KtNamedFunction) -&gt; Transform&lt;KtNamedFunction&gt;<br>): <strong>ExtensionPhase</strong> =<br>  <em>quote</em>(match, map) {<strong> </strong>NamedFunction(it) }</pre><p>Source: <a href="https://github.com/arrow-kt/arrow-meta/blob/master/compiler-plugin/src/main/kotlin/arrow/meta/quotes/MetaExtensions.kt">MetaExtensions.kt</a></p><p>This method allows us to specify a predicate to match a method and a transformation for it. We need to validate a method that has this signature.</p><pre>@DebugLog<br>fun prime(n: Int): Long</pre><p>I created an extension validateFunction on KtNamedFunction that checks whether the function is annotated with DebugLog , has an Int params and a Long return type.</p><pre><em>/**<br> * Match a function that fits this scenario.<br> *<br> * - Function has 1 param that is of Int type.<br> * - Function has a Long return type.<br> * - Function has a DebugLog annotation.<br> */<br></em>private fun KtNamedFunction.validateFunction(): Boolean =<br>        <strong><em>hasOneIntParam</em></strong>() &amp;&amp; <br>        <strong><em>hasLongReturnType</em></strong>() &amp;&amp; <br>        <strong><em>hasAnnotation</em>(<em>DEBUG_LOG</em>)</strong><br></pre><pre><em>/**<br> * Check function has 1 param that is of Int type.<br> */<br></em>private fun KtNamedFunction.<strong>hasOneIntParam</strong>(): Boolean =<br>        <em>valueParameterList</em>?.<em>parameters</em>?.size == 1 &amp;&amp;<br>          <em>valueParameterList</em>?.<em>parameters</em>?.<em>first</em>()<br>                             ?.<em>typeReference</em>?.<em>text </em>== <em>INT<br><br>/**<br> * Check function is returning a Long.<br> */<br></em>private fun KtNamedFunction.<strong>hasLongReturnType</strong>(): Boolean =<br>        hasDeclaredReturnType() &amp;&amp; <em>typeReference</em>?.<em>text </em>== <em>LONG</em></pre><pre><em>/**<br> * Check function has [annotationNames] as an annotation.<br> */<br></em>fun KtAnnotated.<strong>hasAnnotation</strong>(<br>        vararg annotationNames: String<br>): Boolean {<br>    val names = annotationNames.<em>toHashSet</em>()<br>    val predicate: (KtAnnotationEntry) -&gt; Boolean = <strong>{<br>        </strong>it.<em>typeReference<br>                </em>?.typeElement<br>                ?.<em>safeAs</em>&lt;KtUserType&gt;()<br>                ?.<em>referencedName </em>in names<br>    }<strong><br>    </strong>return <em>annotationEntries</em>.<em>any</em>(predicate)<br>}</pre><p>Each requirement that we want to satisfy is specified as an extension. It doesn’t have to be. We check whether there is an annotation on the method by going through any annotationEntries the method may have. We also check if the function has Int param by going through each valueParameterList and checking its typeReference . I could write this to be more general. But, for the sake of simplicity, I constrained it to match a specific signature.</p><p>After a method having a DebugLog annotation is found in the AST, we need to transform it. As a reminder, our goal is to transform the function to:</p><pre>fun prime(n: Int): Long {<br><strong>  println(“-&gt; prime(n=$n)”)</strong><br><strong>  val startTime = System.currentTimeMillis()</strong><br>  val result = listOf(1L,2L,3L).take(n).last()<br><strong>  val timeToRun = System.currentTimeMillis() — startTime</strong><br><strong>  println(“&lt;- prime[ran in $timeToRun ms]”)</strong><br>  return result<br>}</pre><p>To accomplish this, I wrote the following method.</p><pre>fun replace(f<strong>unction: KtNamedFunction</strong>): <strong>String</strong> {<br>    val <strong>functionName</strong> = function.<em>name<br>    </em>val <strong>paramName</strong> = function.<em>valueParameters</em>.<em>first</em>().<em>name<br>    </em>val <strong>functionBody</strong> = function.<em>body</em>()?.<em>bodySourceAsExpression</em>()<br><br>    return &quot;&quot;&quot;<br>        |//metadebug<br>        |<br>        | fun ${<strong>functionName</strong>}(${<strong>paramName</strong>}: Int): Long {<br>        |   println(&quot;-&gt; $<strong>functionName</strong>(${<strong>paramName</strong>}=$${<strong>paramName</strong>})&quot;)<br>        |   val startTime = System.currentTimeMillis()<br>        |   val result = $<strong>functionBody</strong><br>        |   val timeToRun = System.currentTimeMillis() - startTime<br>        |   println(&quot;&lt;- ${<strong>functionName</strong>}[ran in ${&#39;$&#39;}timeToRun ms]&quot;)<br>        |   return result<br>        | }&quot;&quot;&quot;<br>}</pre><p>This method grabs the function name, the first params and the function body first. Then, I return a string that logs the time execution and returns the result from the existing function body.</p><pre>val Meta.<em>debugLog</em>: Plugin<br> get() =<br>   <strong>&quot;</strong>DebugLog<strong>&quot;</strong> {<strong><br>     </strong>meta(<br>       <em>namedFunction</em>({<strong> </strong><em>validateFunction</em>() }) {<strong> </strong>c: KtNamedFunction -&gt;<strong><br>          Transform.replace(<br>            replacing = c,<br>            newDeclaration = <em>replace</em>(c).<em>function<br>          </em>)</strong><br>        }<strong><br>      </strong>)<br>    }</pre><p>We have specified the replacement transformation above. Arrow Meta has support for many types of transformation including removal, new source and transformations could be composed. All of these transforms are <a href="https://github.com/arrow-kt/arrow-meta/blob/master/compiler-plugin/src/main/kotlin/arrow/meta/quotes/Transform.kt">extensions</a> on the Transform type.</p><p>At this point, we have built our plugin that meets the goal we wanted to accomplish. A function annotated with DebugLog is transformed to log its execution time.</p><h3><strong>Usage &amp; Output</strong></h3><p>If we build our project, a jar file will be generated in our create-plugin/build/libs folder. Let’s see our plugin in action. I’m going to create a file with a main method in the use-plugin module.</p><pre>@DebugLog<br>fun prime(n: Int): Long = <em>listOf</em>(1L,2L,3L).<em>take</em>(n).<em>last</em>()<br><br>fun main() {<br>  <em>prime</em>(10)<br>}</pre><p>If I were to run this method, this will be the output as expected.</p><pre>-&gt; prime(n=10)<br>&lt;- prime[ran in 36 ms]</pre><h3><strong>Testing</strong></h3><p>Arrow meta has thetesting-plugin module that provides utilities for ensuring our plugin functions as we expect it.</p><pre>class DebugLogMetaPluginTest {<br><br>    companion object {<br><br>        val <strong>debuglog</strong> = &quot;&quot;&quot;<br>            |annotation class DebugLog<br>            |<br>            |@DebugLog<br>            |fun prime(n: Int): Long =  <br>            |       listOf(1L,2L,3L).take(n).last()<br>            | &quot;&quot;&quot;.<em>trimMargin</em>().<em>trim</em>().<em>source<br><br>        </em>val <strong>expectedOutput</strong> = &quot;&quot;&quot;<br>            |annotation class DebugLog<br>            |<br>            |//metadebug<br>            |fun prime(n: Int): Long {<br>            | println(&quot;-&gt; prime(n=${&#39;$&#39;}n)&quot;)<br>            | val startTime = System.currentTimeMillis()<br>            | val result = listOf(1L,2L,3L).take(n).last()<br>            | val timeToRun = System.currentTimeMillis() - startTime<br>            | println(&quot;&lt;- prime[ran in ${&#39;$&#39;}timeToRun ms]&quot;)<br>            | return result<br>            | }&quot;&quot;&quot;.<em>trimMargin</em>().<em>trim</em>().<em>source<br>    </em>}<br>}</pre><p>For my test above, I have specified two string that presents the input source and expected source after the transformed is applied to the plugin.</p><pre>@Test<br>fun `should print function time execution`() {<br>    <em>assertThis</em>(<strong>CompilerTest</strong>(<br>     config = {<strong> </strong><em>listOf</em>(addMetaPlugins(<strong>DebugLogMetaPlugin()</strong>)) },<br>          <strong>code</strong> = {<strong> </strong>debuglog },<br>          <strong>assert</strong> = {<strong> quoteOutputMatches(</strong>expectedOutput<strong>)</strong> }<strong><br>    </strong>))<br>}</pre><p>The testing-plugin module provides a CompileTest that allows you to specify the code you want to transform and what it should assert with. The test above internally creates a file Source.kt that intercepts the analysis phase of the compiler and applies the transformation on my code. Arrow Meta provides helpful logging information as your test runs.</p><pre><strong>Replacing</strong> class arrow.meta.internal.kastree.ast.Node$Decl$Func with [class org.jetbrains.kotlin.psi.KtNamedFunction]: newContents: <br>//metadebug<br>fun prime(n: Int): Long {<br>   println(&quot;-&gt; prime(n=$n)&quot;)<br>   val startTime = System.currentTimeMillis()<br>   val result = listOf(1L,2L,3L).take(n).last()<br>   val timeToRun = System.currentTimeMillis() - startTime<br>   println(&quot;&lt;- prime[ran in $timeToRun ms]&quot;)<br>   return result<br> }<br><strong>Transformed</strong> file: KtFile: Source.kt. New contents: <br>[(KtFile: Source.kt, annotation class DebugLog</pre><pre>//metadebug<br>fun prime(n: Int): Long {<br>   println(&quot;-&gt; prime(n=$n)&quot;)<br>   val startTime = System.currentTimeMillis()<br>   val result = listOf(1L,2L,3L).take(n).last()<br>   val timeToRun = System.currentTimeMillis() - startTime<br>   println(&quot;&lt;- prime[ran in $timeToRun ms]&quot;)<br>   return result<br> }<br>)]<br><strong>END quote.doAnalysis</strong>: <strong>[KtFile: Source.kt]</strong></pre><p>There is a system internally called <strong>Quote</strong> that drives all the transformation. This is how you test a compiler plugin with Arrow Meta.</p><h3><strong>Conclusion</strong></h3><p>I hope that was helpful for you as you create your own Compiler Plugins with Arrow Meta. There is a LOT more you could do. Thanks to Raul Raja, Rachel M. Carmena, Amanda Hinchman and more for creating a very cool tool. This project also contains many examples of how to create a functional API. You could check out my plugin <a href="https://github.com/msya/debuglog-arrow-meta">debuglog-arrow-meta.</a> Arrow Meta is still in development. But, I started to use Arrow Meta for complex use cases and I very much enjoy it. If you have any questions, please leave a response.</p><h3>Resources</h3><ul><li><a href="https://github.com/arrow-kt/arrow-meta-examples">Arrow Meta Examples</a></li><li><a href="https://www.youtube.com/watch?v=WKR384ZeBgk">Lambda World 2019 — Arrow Meta — Enabling Functional Programming in the Kotlin Compiler</a></li><li><a href="https://www.youtube.com/watch?v=LT6m5_LO2DQ">DroidCon NYC 2018 — Static Code Analysis with Kotlin</a></li></ul><p><em>Follow me on Twitter</em><strong><em>: </em></strong><a href="https://twitter.com/heyitsmohit">https://twitter.com/heyitsmohit</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cf7b3689aa3e" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Unit Testing Delays, Errors & Retries with Kotlin Flows]]></title>
            <link>https://medium.com/@heyitsmohit/unit-testing-delays-errors-retries-with-kotlin-flows-77ce00d0c2f3?source=rss-9057ae5f9de4------2</link>
            <guid isPermaLink="false">https://medium.com/p/77ce00d0c2f3</guid>
            <category><![CDATA[androiddev]]></category>
            <category><![CDATA[kotlin]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[kotlin-coroutines]]></category>
            <dc:creator><![CDATA[Mohit Sarveiya]]></dc:creator>
            <pubDate>Thu, 19 Mar 2020 23:33:09 GMT</pubDate>
            <atom:updated>2020-03-19T23:33:09.302Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KznKUU2pClbAE1C6P5MOnw.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@alschim?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Alexander Schimmeck</a> on <a href="https://unsplash.com/s/photos/delays?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p><em>Follow me on Twitter: </em><a href="http://www.twitter.com/heyitsmohit"><em>www.twitter.com/heyitsmohit</em></a></p><p>In February, I gave a presentation at the <a href="https://www.meetup.com/nyandroiddevelopers/events/268273123/">NY Android Meetup </a>on unit testing Channels and Flows with practical use cases. In this blog post, I will share with you how to test delays, retries, and errors with Flows. I’ve also added useful tips and things to watch out for when unit testing.</p><h3><strong>Use Case</strong></h3><p>Before, we could write unit tests. We need a use case. Suppose we are building a feature in an app that displays user details. We may have a setup as shown below.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*pff7dHCCDn8byMt5XvfBDg.png" /></figure><p>We have a Repository that goes out to the API and gets the user’s details and gives it to the View Model to display it to the UI. In this article, I will focus on creating the repository and testing it. How would we go about implementing the Repository using a Flow?</p><h4><strong>Repository</strong></h4><p>The <a href="https://developer.android.com/jetpack/docs/guide#fetch-data">repository</a> will use an API service to get the user’s details. We could implement this using <a href="https://square.github.io/retrofit/">Retrofit</a> which has support for suspending functions.</p><pre>interface ApiService {<br>    <a href="http://twitter.com/GET">@GET</a>(&quot;/users/{id}&quot;)<br>    <strong>suspend</strong> fun userDetails(<a href="http://twitter.com/Path">@Path</a>(&quot;id&quot;) id: Int): UserDetails<br>}</pre><p>In this API service, we are going to hit an endpoint that takes an id and return the data in a UserDetails response.</p><pre>fun &lt;T&gt; <strong>flow</strong>(<br>    block: suspend <strong>FlowCollector</strong>&lt;T&gt;.() -&gt; Unit<br>): Flow&lt;T&gt;</pre><p>Source: <a href="https://github.com/Kotlin/kotlinx.coroutines/blob/master/kotlinx-coroutines-core/common/src/flow/Builders.kt#L49">Builders.kt</a></p><p>Using theflow method, we could implement our Repository as follows.</p><pre>class UserRepository(val apiService: ApiService) {<br> <br>    fun userDetails(id: Int): Flow&lt;Result&lt;UserDetails&gt;&gt; {<br>         return <strong>flow</strong> {<br>            val users = apiService.userDetails(id)<br>            <strong>emit</strong>(Result.success(users))<br>         }<br>    }<br>}</pre><p><strong>Tips</strong></p><p>This Flow is emitting a single item. I could the <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/single.html">single</a> method on the Flow and have the userDetails return Result&lt;UserDetails&gt;. However, the restriction on using Result type is that it can’t be returned from a method. This restriction will be lifted in Kotlin 1.4.0.</p><p>This could be implemented without using Flows. But, I want to use a simple example to illustrate testing Flows.</p><p><strong>Error Handling</strong></p><p>What happens if an error occurs in our example? If the method apiService.userDetails(id) throws an exception, it will cause a crash if not handled properly. Here is an example of collecting from a Flow inside of a coroutine launched in a view model scope. It would crash due to the exception.</p><pre>viewModelScope.launch {<br>     val flow = repository.getUserDetails(&quot;id&quot;)<br>     flow.collect { result: Result&lt;UserDetails&gt;<br>          showUI(result.data)<br>     }<br>}</pre><p>There are three ways to handle exceptions.</p><ol><li>Provide an <a href="https://kotlinlang.org/docs/reference/coroutines/exception-handling.html#coroutineexceptionhandler">exception handler</a> to the coroutine in the launch method.</li><li>Use a try and catch around the getUserDetails method.</li><li>Catch the exception in the Flow.</li></ol><p>All of these approaches are valid depending on your use case. I will show you how to use the third approach.</p><pre>class UserRepository(val apiService: ApiService) {<br> <br>  fun userDetails(id: Int): Flow&lt;Result&lt;UserDetails&gt;&gt; {<br>       return flow<em> </em>{<br>           val users = apiService.userDetails(id)<br>           emit(Result.success(users))<br>      }</pre><pre>    <strong>.catch { throwable -&gt;<br>         emit(Result.error(throwable))<br>     }</strong><br>  }    <br>}</pre><p>The <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/catch.html">catch</a> extension on a Flow intercepts the exception. We then emit it in a wrapper type like a Result. That’s exactly what I’m doing above using Result.error(throwable) . With this approach, the exception is caught and won’t crash our application. Instead, it will be incorporated into our Result type.</p><p><strong>Retry</strong></p><p>If an error happens, I may want to retry the request a number of times. The coroutines library provides a <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/retry.html">retry</a> extension that allows you to specify the number of retries and when to perform it. Using the retry extension, our Repository will now look as follows.</p><pre>class UserRepository(val apiService: ApiService) {<br> <br>  fun userDetails(id: Int): Flow&lt;Result&lt;UserDetails&gt;&gt; {<br>       return flow<em> </em>{<br>           val users = apiService.userDetails(id)<br>           emit(Result.success(users))<br>      }<br>      <strong>.retry(2) { e -&gt;<br>         (e is Exception).also { if (it) delay(1000) }<br>      }</strong><br>      .catch { throwable -&gt;<br>         emit(Result.error(throwable))<br>     }<br>}</pre><p>I am specifying that I want to perform two retries when an exception occurs. However, before retrying the request, I will delay the coroutine for one second. Each retry will execute the Flow block again.</p><p><strong>Dispatcher</strong></p><p>In order to test delays and have control over them, we need to be able to inject a dispatcher. Currently, our repository will use a dispatcher from the coroutine it is called from. But, it is a good practice to explicitly inject into the repository which dispatcher the Flow will use. The coroutines test library provides a test dispatcher that allows us to control virtual time. We could modify our repository to take in a dispatcher in its constructor.</p><pre>class UserRepository(<br>    val apiService: ApiService,<br><strong>    val dispatcher: CoroutineDispatcher</strong><br>) {<br> <br>  fun userDetails(id: Int): Flow&lt;Result&lt;UserDetails&gt;&gt; {<br>       return flow<em> </em>{<br>           val users = apiService.userDetails(id)<br>           emit(Result.success(users))<br>      }<br>      .retry(2) { e -&gt;<br>         (e is Exception).also { if (it) delay(1000) }<br>      }<br>      .catch { throwable -&gt;<br>         emit(Result.error(throwable))<br>     }<br>     <strong>.flowOn(dispatcher)</strong>   <br>  }<br>}</pre><p>The injected dispatcher is used in the Flow by using the <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/flow-on.html">flowOn</a> extension. This means everything before flowOn method which is the retry, catch and the flow block itself will run on the inject dispatcher.</p><p><strong>Tips</strong></p><p>A common pattern followed in the community is to inject a provider for the dispatcher. The provider could give you a <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/">Dispatchers.IO</a> or <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/">Dispatchers.Default</a>.</p><h3><strong>Unit Tests</strong></h3><p>How do we unit test the repository? There are three cases we want to test in our example.</p><ol><li>Flow emits successfully.</li><li>Flow completes all retries with an error.</li><li>Flow retries and a successful response occurs.</li></ol><h4><strong>Test Success</strong></h4><p>How do we test the simplest case of a successful emission? We need to mock the API service to return data. I will use <a href="https://github.com/nhaarman/mockito-kotlin">mockito-kotlin</a> for stubbing our API service.</p><pre>class UserRepositoryTest {</pre><pre>    val testDispatcher = TestCoroutineDispatcher()<br>    val apiService = mock&lt;ApiService&gt;()<br>    val repository = UserRepository(apiService, testDispatcher)<br>}</pre><p>Create the repository we will test with that takes a test dispatcher and a mocked API service. In order to write our test case, we have to create a coroutine that our test will run in. There are two methods we could use from the coroutine library to do this.</p><ol><li><a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html">runBlocking</a></li><li><a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/kotlinx.coroutines.test/run-blocking-test.html">runBlockingTest</a></li></ol><p>The runBlocking method is good for testing non-delays while runBlockingTest gives you finer control over virtual time if you need it. For the successful case, we will use runBlocking to create a coroutine.</p><pre>class UserRepositoryTest {</pre><pre>    val testDispatcher = TestCoroutineDispatcher()<br>    val apiService = mock&lt;ApiService&gt;()<br>    val repository = UserRepository(apiService, testDispatcher)</pre><pre>    @Test<strong><br>    </strong>fun `flow emits successfully`() = runBlocking {<br>         <br>         <strong>// Mock API Service</strong><br>         val userDetails = UserDetails(1, &quot;User 1&quot;, &quot;avatar_url&quot;)<br>         userService.<em>stub </em>{<strong><br>             </strong><em>onBlocking </em>{<strong> </strong>userDetails(1) }<strong> </strong><em>doReturn </em>userDetails<br>         }</pre><pre>         <strong>// Test</strong><br>         val flow = repository.getUserDetails(id = 1)</pre><pre>         <strong>// Verify</strong><br>         flow.collect {<strong> </strong>result: Result&lt;UserDetails&gt; -&gt;<strong><br>              </strong>result.isSuccess.<em>shouldBeTrue</em>()<br>              result.<em>onSuccess </em>{<strong><br>                 </strong>it<strong> </strong><em>shouldBeEqualTo </em>userDetails<br>              }<strong><br>         </strong>}<br>     }<br>}</pre><p>There are three steps in this test — mock, test and verify. In the mocking test,</p><p><em>Mock API Service</em></p><p>I am stubbing out the API service to return a mock UserDetails response. Since the userDetails method is a suspending function, I cannot use <br>on { userDetails(id = 1) } doReturn userDetails. It will give an error that a suspending method can only be called from another suspending method. The lambda block of the onmethod is not suspending. Mockito-kotlin provides an <a href="https://github.com/nhaarman/mockito-kotlin/blob/3139a2c470e6cc9425b016e3d2267aaf7e9baa87/mockito-kotlin/src/main/kotlin/com/nhaarman/mockitokotlin2/KStubbing.kt#L79">onBlocking</a> method that takes in a suspending lambda and stubs the method out in a runBlocking coroutine.</p><p><em>Test &amp; Verify</em></p><p>In the test phase, I get the Flow from the repository, collect from it and verify the data in the result. I am using the library <a href="https://markusamshove.github.io/Kluent/">Kluent</a> for verification. It provides methods such as shouldBeTrue and shouldBeEqualTo.</p><p><strong>Tips</strong></p><p>There is a library called <a href="https://mockk.io/">MockK</a> that provides methods to verify Flow assertions. In the community, libraries have also built patterns to performs assertions. Check out the SQL Delight’s library <a href="https://github.com/cashapp/sqldelight/blob/master/extensions/coroutines-extensions/src/commonTest/kotlin/com/squareup/sqldelight/runtime/coroutines/FlowAssert.kt">FlowAssert</a> pattern.</p><h4><strong>Test Retry</strong></h4><p>How do we test that the Flow handles exceptions and retries? There are two retry cases we want to test.</p><ol><li>Flow completes all retries with an error.</li><li>Flow retries and a successful response occurs.</li></ol><p>Let’s start with the first test case.</p><ol><li>Flow completes all retries with an error.</li></ol><pre>@Test<br>fun `should retry with error`() = <br>  <strong>testCoroutineDispatcher.<em>runBlockingTest</em></strong><em> </em>{<strong><br>      </strong>userService.<em>stub </em>{<strong><br>        </strong><em>onBlocking </em>{<strong> </strong>userDetails(1) }<strong> </strong><em>doAnswer </em>{<strong><br>            </strong>throw IOException()<br>        }<strong><br>    </strong>}<strong><br><br>    </strong>val flow = repository.getUserDetails(id = 1)<br><br>    flow.collect {<strong> </strong>result: Result&lt;UserDetails&gt; <strong>-&gt;<br>        </strong>result.isFailure.<em>shouldBeTrue</em>()<br>    }<strong><br></strong>}</pre><p>In our Repository, when an error occurs, we delay for 1 second before executing the flow block again.</p><pre>flow<em> </em>{<br>    val users = apiService.userDetails(id)<br>    emit(Result.success(users))<br>}.<strong>retry(2) { e -&gt;<br>    (e is Exception).also { if (it) delay(1000) }<br>}</strong>.catch { throwable -&gt;<br>     emit(Result.error(throwable))<br>}.flowOn(dispatcher)</pre><p>As we have delays in our code, we will use therunBlockingTest method in our test.</p><p>What does runBlockingTest do?</p><p>This method creates a coroutine with a TestCoroutineScope that has a TestCoroutineDispatcher and a TestCoroutineExceptionHandler . This method takes in a lambda block testBody and an optional context .</p><pre>fun runBlockingTest(<br>   context: CoroutineContext = EmptyCoroutineContext, <br>   <strong>testBody</strong>: suspend TestCoroutineScope.() -&gt; Unit<br>)</pre><p>In my test, I am using this method as</p><pre><strong>testCoroutineDispatcher.<em>runBlockingTest </em></strong><em>{<br>    ...<br></em>}</pre><p>This will create a coroutine with our own customtestCoroutineDispatcher<strong>.</strong></p><p>This is equivalent to:</p><pre><strong><em>runBlockingTest(</em>testCoroutineDispatcher<em>) </em></strong><em>{<br>    ...<br></em>}</pre><p>However, an extension is provided on runBlockingTest that I am using to provide my own dispatcher.</p><pre>fun <strong>TestCoroutineDispatcher.runBlockingTest</strong>(<br>    block: suspend TestCoroutineScope.() -&gt; Unit<br>)</pre><p>Source: <a href="https://github.com/Kotlin/kotlinx.coroutines/blob/d7de5f5ba66a8d005e5cbd03b18522112303fd54/kotlinx-coroutines-test/src/TestBuilders.kt#L78">TestBuilders.kt</a></p><p>After creating the coroutine my test will run in, I am mocking my API service to throw an exception. Then, I proceed to collect from my Flow and perform an assertion.</p><pre>@Test<br>fun `should retry with error`() = <br>  testCoroutineDispatcher.<em>runBlockingTest </em>{</pre><pre><strong>      // Mock<br>      </strong>userService.<em>stub </em>{<strong><br>         </strong><em>onBlocking </em>{<strong> </strong>userDetails(1) }<strong> </strong><em>doAnswer </em>{<strong><br>             </strong>throw IOException()<br>         }<strong><br>     </strong>}<strong><br><br>      // Test<br>      </strong>val flow = repository.getUserDetails(id = 1)</pre><pre><strong>      // Verify</strong><br>      flow.collect {<strong> </strong>result: Result&lt;UserDetails&gt; <strong>-&gt;<br>         </strong>result.isFailure.<em>shouldBeTrue</em>()<br>      }<strong><br></strong>}</pre><p>Let’s trace how this test runs. If I add logs or add breakpoints in the IDE, it will help visualize what happens.</p><pre>fun getUserDetails(id: Int): Flow&lt;Result&lt;UserDetails&gt;&gt; {<br>    return <em>flow </em>{<strong><br>        <em>println</em>(&quot;STARTING FLOW&quot;)</strong><br>        val users = userService.userDetails(id)<br>        emit(Result.success(users))<br>    }<strong><br>    </strong>.<em>retry</em>(retries = 2) {<strong> </strong>t<strong> -&gt;<br>        <em>println</em>(&quot;RETRY&quot;)</strong><br>        (t is IOException).<em>also </em>{ <strong><br>            </strong>if (<strong>it</strong>) { <br><strong>                <em>println</em>(&quot;BEFORE DELAY&quot;)</strong><br>                delay(<em>DELAY_ONE_SECOND</em>)<br>                <strong><em>println</em>(&quot;AFTER DELAY&quot;)</strong><br>            }<br>        <strong>}<br>    }<br>    </strong>.<em>catch </em>{<strong><br>        <em>println</em>(&quot;CATCH&quot;)</strong><br>        emit(Result.failure(it))<br>    }.<em>flowOn</em>(dispatcher)<br>}</pre><p>Here is the output of running the test.</p><pre>// Initial Run of Flow<br>STARTING FLOW</pre><pre>// 1st Retry<br>RETRY<br>BEFORE DELAY<br>AFTER DELAY<br>STARTING FLOW</pre><pre>// 2nd Retry<br>RETRY<br>BEFORE DELAY<br>AFTER DELAY<br>STARTING FLOW</pre><pre>// Both retries failed run catch block<br>CATCH</pre><p><em>Initial Run of Flow</em></p><p>When I collect from the Flow in the test, it will execute the flow block and an exception will be thrown since we used doAnswer to train our Api Service to throw an IOException.</p><p><em>1st and 2nd Retry</em></p><p>It will then go into the retry block and delay for one second. After the delay, it will execute the Flow block again. An exception will occur again. This process will repeat itself for the 2nd retry.</p><p><em>Catch Error</em></p><p>Since we only specified two retries, it will finally halt the retries and go into the catch block since all retries failed and emit the error.</p><h4><strong>Under the hood</strong></h4><p>Under the hood, the TestCoroutineDispatcher has a queue which is an event loop.</p><pre>// The ordered queue for the runnable tasks.<br>private val queue = ThreadSafeHeap&lt;TimedRunnable&gt;()</pre><p>Source: <a href="https://github.com/Kotlin/kotlinx.coroutines/blob/d7de5f5ba66a8d005e5cbd03b18522112303fd54/kotlinx-coroutines-test/src/TestCoroutineDispatcher.kt#L39">TestCoroutineDispatcher</a></p><p>Every time it dispatches, it adds an TimedRunnable object to the queue. This object contains the Runnable task and a time to perform the task.</p><pre>private fun post(block: Runnable) =              <br>     queue.addLast(<br>        TimedRunnable(block, _counter.getAndIncrement())<br>     )</pre><pre>class TimedRunnable(<br>    @JvmField val runnable: Runnable,<br>    private val count: Long = 0,<br>    @JvmField val time: Long = 0<br>)</pre><p>Source: <a href="https://github.com/Kotlin/kotlinx.coroutines/blob/d7de5f5ba66a8d005e5cbd03b18522112303fd54/kotlinx-coroutines-test/src/TestCoroutineDispatcher.kt#L200">TimedRunnable</a></p><p>As time is advanced forward on the test dispatcher, the Runnable tasks are executed.</p><p>When you look at this test, I am not explicitly advancing time forward. How does it move virtual time forward?</p><pre>@Test<br>fun `should retry with error`() = <br>  testCoroutineDispatcher.<em>runBlockingTest </em>{<strong><br>      </strong>userService.<em>stub </em>{<strong><br>        </strong><em>onBlocking </em>{<strong> </strong>userDetails(1) }<strong> </strong><em>doAnswer </em>{<strong><br>            </strong>throw IOException()<br>        }<strong><br>    </strong>}<strong><br><br>    </strong>val flow = repository.getUserDetails(id = 1)<br><br>    flow.collect {<strong> </strong>result: Result&lt;UserDetails&gt; <strong>-&gt;<br>        </strong>result.isFailure.<em>shouldBeTrue</em>()<br>    }<strong><br></strong>}</pre><p>Let’s look under the hood at the implementation of runBlockingTest . You will see that it will advance time forward until there are no more runnables to execute for all of your test.</p><pre>val startingJobs = safeContext.<em>activeJobs</em>()<br>val scope = <em>TestCoroutineScope</em>(safeContext)<br>val deferred = scope.<em>async </em>{<strong><br>    </strong>scope.testBody()<br>}<strong><br>dispatcher.advanceUntilIdle()</strong><br>deferred.getCompletionExceptionOrNull()?.<em>let </em>{<strong><br>    </strong>throw it<strong><br></strong>}<strong><br></strong>scope.cleanupTestCoroutines()<br>val endingJobs = safeContext.<em>activeJobs</em>()<br>if ((endingJobs - startingJobs).<em>isNotEmpty</em>()) {<br>    throw UncompletedCoroutinesError(<br>         &quot;Test finished with active jobs: $endingJobs&quot;<br>    )<br>}</pre><p>Source: <a href="https://github.com/Kotlin/kotlinx.coroutines/blob/d7de5f5ba66a8d005e5cbd03b18522112303fd54/kotlinx-coroutines-test/src/TestCoroutineDispatcher.kt#L200">TestCoroutineDispatcher</a></p><p>dispatcher.advanceUntilIdle() will advance the delays in our tests. In my tests, I am leveraging this to go through all the retries with delays and emit an error. This is how it works under the hood.</p><p><strong>Tips</strong>:</p><p>The most common error you will get is Test finished with active jobs error when you use runBlockingTest . This happens, because you have an active coroutine running in your test. For example, if you had a producer using a Rendezvous Channel and you had called send and didn’t receive the value, you will get this error. That’s only one example of it. So, watch out for that error.</p><h4><strong>Test Retry with Success</strong></h4><p>2. Flow retries and a successful response occurs.</p><p>How do we test that a retry actually succeeds and emits the data?</p><pre>@Test<br>fun `should retry with success`() <br>    testCoroutineDispatcher.<em>runBlockingTest </em>{    <strong><br>        <br>       // Mock<br>       </strong>var throwError = true<br>       val userDetails = UserDetails(1, &quot;User 1&quot;, &quot;avatar_url&quot;)<br><br>       userService.<em>stub </em>{<strong><br>           </strong><em>onBlocking </em>{<strong> </strong>userDetails(1) }<strong> </strong><em>doAnswer </em>{<strong><br>            </strong>if (throwError) throw IOException() else userDetails<br>          }<strong><br>        </strong>}</pre><pre><strong>       // Test<br>       </strong>val flow = repository.getUserDetails(id = 1)</pre><pre>       // <strong>Verify</strong><br>       <em>launch </em>{<strong><br>          </strong>flow.collect {<strong> </strong>result -&gt;<strong><br>              </strong>result.isSuccess.<em>shouldBeTrue</em>()<br>          }<strong><br>       </strong>}</pre><pre><strong>       // 1st Retry<br>       </strong>advanceTimeBy(DELAY_ONE_SECOND)</pre><pre>       // <strong>2nd Retry</strong><br>       throwError = false<br>       advanceTimeBy(DELAY_ONE_SECOND)<br><strong>}</strong></pre><p>In this test, I am controlling whether an exception will be thrown or a successful response be given by using thethrowError variable.</p><pre>var <strong>throwError</strong> = true<br>val userDetails = UserDetails(1, &quot;User 1&quot;, &quot;avatar_url&quot;)<br><br>userService.<em>stub </em>{<strong><br>   </strong><em>onBlocking </em>{<strong> </strong>userDetails(1) }<strong> </strong><em>doAnswer </em>{<strong><br>      </strong>if (<strong>throwError</strong>) throw IOException() else userDetails<br>   }<strong><br></strong>}</pre><p>I am collecting from the Flow in a child coroutine. This coroutine is the consumer. If I didn’t launch a child coroutine, this test would fail.</p><pre><em>launch </em>{<strong><br>  </strong>flow.collect {<strong> </strong>result -&gt;<strong><br>     </strong>result.isSuccess.<em>shouldBeTrue</em>()<br>   }<strong><br></strong>}</pre><p>I want to be able to advance time forward when it encounters a delay so that the first retry fails. But, I want the second retry to pass. I will setthrowError to false so that when the flowblock is executed it succeeds with data.</p><pre><strong>// 1st Retry<br></strong>advanceTimeBy(DELAY_ONE_SECOND)</pre><pre>// <strong>2nd Retry</strong><br>throwError = false<br>advanceTimeBy(DELAY_ONE_SECOND)</pre><p><strong>Tips:</strong></p><p>Watch out for an undocumented edge case of runBlockingTest . If you wrote a test that has multiple errors, runBlockingTest will drop the first one. See <a href="https://github.com/Kotlin/kotlinx.coroutines/blob/master/kotlinx-coroutines-test/src/TestCoroutineExceptionHandler.kt#L59">TestCoroutineExceptionHandler</a>.</p><h4><strong>Resources</strong></h4><ul><li><a href="https://speakerdeck.com/heyitsmohit/unit-testing-kotlin-channels-and-flows">Unit Testing Channels &amp; Flow in Practice</a></li><li><a href="https://www.youtube.com/watch?v=hMFwNLVK8HU">Testing with Coroutines</a></li></ul><p>I hope that was helpful to you. If you practice writing lots of tests using runBlockingTest for different scenarios, then it will get easier. If you have any questions, please let me know in the response. I gave more examples in my presentation. Please check out my slides on <a href="https://speakerdeck.com/heyitsmohit/unit-testing-kotlin-channels-and-flows">Unit Testing Channels &amp; Flow in Practice</a>.</p><p><em>Follow me on Twitter: </em><a href="https://twitter.com/heyitsmohit"><em>www.twitter.com/heyitsmohit</em></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=77ce00d0c2f3" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Combining Kotlin Flows with Select Expressions]]></title>
            <link>https://proandroiddev.com/combining-kotlin-flows-with-select-expressions-cbe419ba515f?source=rss-9057ae5f9de4------2</link>
            <guid isPermaLink="false">https://medium.com/p/cbe419ba515f</guid>
            <category><![CDATA[kotlin]]></category>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[kotlin-coroutines]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[coroutine]]></category>
            <dc:creator><![CDATA[Mohit Sarveiya]]></dc:creator>
            <pubDate>Sun, 01 Mar 2020 23:31:05 GMT</pubDate>
            <atom:updated>2020-03-10T16:55:27.969Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*c8O7LcqWzMUFIOusx5Fw7A.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@boudewijnboer?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Boudewijn “Bo” Boer</a> on <a href="https://unsplash.com/s/photos/amsterdam?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p><em>Follow me on Twitter </em><a href="https://twitter.com/heyitsmohit"><em>https://twitter.com/heyitsmohit</em></a></p><p>How do we combine emissions from multiple Flows? We could use operators such as <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/zip.html">zip</a>, <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/flatten-merge.html">flattenMerge</a> and <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/combine.html">combine</a>. This article will explore how to use the combine operator and how it works under the hood. Interestingly, it uses an <a href="https://kotlinlang.org/docs/reference/experimental.html">experimental</a> construct called a <a href="https://kotlinlang.org/docs/reference/coroutines/select-expression.html">Select expression</a>. We will look at how the select expressions work and how they are used internally in the combine operator.</p><h3>Combining Flows</h3><p><strong>Use Case</strong></p><p>Let’s start with a simple example of combing two streams together.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*dGwDyiuGX9ZlcGgjHtolwQ.png" /></figure><p>In the diagram above, we have two Flows that are emitting items at different times. The first Flow is emitting numbers 1, 2 and 3 every second. The second Flow is emitting letters A, B, and C every 2 seconds. How do we combine these emissions?</p><pre>fun main() = runBlocking {</pre><pre>    val numbersFlow = flowOf(1,2,3).delayEach(1000)<br>    val lettersFlow = flowOf(&quot;A&quot;, &quot;B&quot;,&quot;C&quot;).delayEach(2000)<br>    <br>    numbersFlow.<strong>combine</strong>(lettersFlow) { number, letter -&gt;<br>         &quot;$number$letter&quot;<br>    }.collect {<br>        println(it)<br>    }<br>    <br>}</pre><p>In the code snippet above, I have implemented our example of two Flows each emitting at different times.</p><pre>val numbersFlow = flowOf(1,2,3).<strong>delayEach</strong>(1000)<br>val lettersFlow = flowOf(&quot;A&quot;, &quot;B&quot;,&quot;C&quot;).<strong>delayEach</strong>(2000)</pre><p>Let’s look at the signature of the <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/combine.html">combine</a> operator. It is an extension on Flow that takes as an argument another Flow to combine with. The second argument it accepts is a lambda which gives you values <strong>a: T1 </strong>and <strong>b: T2 </strong>that were emitted <em>most recently</em> both Flows. This lambda represents the transformation you want to perform on the emissions from both Flows.</p><pre><a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html">Flow</a>&lt;<a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/combine.html#T1">T1</a>&gt;.combine(<br>    <strong>flow</strong>: <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html">Flow</a>&lt;<a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/combine.html#T2">T2</a>&gt;,<br>    <strong>transform</strong>: suspend (<strong>a</strong>: <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/combine.html#T1">T1</a>, <strong>b</strong>: <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/combine.html#T2">T2</a>) -&gt; <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/combine.html#R">R</a><br>): <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html">Flow</a>&lt;<a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/combine.html#R">R</a>&gt; <a href="https://github.com/kotlin/kotlinx.coroutines/tree/master/kotlinx-coroutines-core/common/src/flow/operators/Zip.kt#L34">(source</a>)</pre><p>This how we could use this operator for our example.</p><pre>numbersFlow.<strong>combine</strong>(lettersFlow) { <strong>number</strong>, <strong>letter</strong> -&gt;<br>    &quot;$number$letter&quot;<br>}.collect {<br>     println(it)<br>}</pre><pre>Output<br>1A <br>2A <br>3A <br>3B <br>3C</pre><p>I have specified the transformation to concatenate the number and letter. We print out the result of the transformation when collecting from the Flow. Let’s understand why the combine operator produces this output.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*swK1fCaW6jgtzCnjM6Cm-Q.png" /><figcaption>Flow Combine</figcaption></figure><p><strong>How combine operator works?</strong></p><blockquote>The combine operator returns a Flow whose values are generated with transform function by combining the most recently emitted values by each flow.</blockquote><ul><li>The first two values emitted by the numbers and letters Flow is 1 and A, respectively. These two values are combined together to produce 1A.</li><li>The numbers Flow is first to emit as it emits faster than the letters Flow. It emits the value of 2. At this point, the letters Flow is suspended. It hasn’t emitted anything. What will we combine with? We will combine with the letter Flow’s <em>most</em> <em>recently</em> emitted value of A. This will produce 2A.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/298/1*GaoeuwlQnMAMr1_3ZqWrPw.png" /></figure><ul><li>The letters Flow now emits the value of 3. This will follow the same logic and it will combine with the <em>most recently emitted</em> value of A. Thus producing 3A .</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/398/1*vm2n00wtNO6PYmjbXEBEgw.png" /></figure><ul><li>Finally, the letters Flow emits the value of B after delaying for 2 seconds. It will combine with the <em>most recently emitted</em> value of 3 from the numbers Flow producing 3B .</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/470/1*d-cPtvEzoqbeom_pIx7Lbw.png" /></figure><ul><li>At this point, everything has been emitted from the numbers Flow. The final emission from the letters Flow is C. It is combined with 3 to get a value of 3C.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/570/1*tOb9mTERbiVu9LYZwXONNQ.png" /></figure><p>This is the trace of how the emissions are combined from each Flow. Feel free to run the code above and familiarize yourself with the combine operator.</p><p>How does the combine operator listen to two Flows emitting at different rates? This is accomplished by using select expressions. They are experimental but they are used in the implementations of the zip and the combine operator. Let’s see how it works.</p><h3>Select Expressions</h3><blockquote>A <a href="https://kotlinlang.org/docs/reference/coroutines/select-expression.html">select expression</a> is a construct that allows you to listen to multiple suspending coroutines <em>simultaneously.</em></blockquote><p><strong>Use Case</strong></p><p>Suppose we have two coroutines that are sending values to a Channel. Producer 1 delays for 1 second and send a value while Producer 2 delays for 2 seconds before sending a value. These coroutines are created by using the <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/produce.html">produce</a> builder. It provides a Channel for you to send values to it and gives you back a <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/index.html">RecieveChannel</a> instance to read values.</p><pre>fun CoroutineScope.<strong>producer1</strong>() = <em>produce</em>&lt;String&gt; <strong>{<br>    </strong>while (true) {<br>        <em>delay</em>(1000)<br>        send(&quot;Producer Item 1&quot;)<br>    }<br><strong>}</strong></pre><pre>fun CoroutineScope.<strong>producer2</strong>() = <em>produce</em>&lt;String&gt; <strong>{<br>    </strong>while (true) {<br>        <em>delay</em>(2000)<br>        send(&quot;Producer Item 2&quot;)<br>    }<br><strong>}</strong></pre><p>We could receive values from <em>either</em> of these producers as shown below.</p><pre>val channel1: <strong>ReceiveChannel</strong> = producer1()<br>val channel2: <strong>ReceiveChannel</strong> = producer2()</pre><pre>val item1: String = channel1.<strong>receive</strong>()<br>val item2: String = channel2.<strong>receive</strong>()</pre><p>But, suppose I want to receive values <em>simultaneously</em> from either producer. In order to do this, we will need to use a Select expression.</p><p>A Select expression takes a lambda block which allows you to use <em>clauses</em> inside of it to listen for values from multiple Channels.</p><pre>inline suspend fun &lt;R&gt; select(<br>    crossinline <strong>builder</strong>: <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.selects/-select-builder/index.html">SelectBuilder</a>&lt;<a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.selects/select.html#R">R</a>&gt;.() -&gt; <a href="https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html">Unit</a><br>): <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.selects/select.html#R">R</a> <a href="https://github.com/kotlin/kotlinx.coroutines/tree/master/kotlinx-coroutines-core/common/src/selects/Select.kt#L173">(source)</a></pre><p>Source: <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.selects/select.html">Select</a></p><p>How do we create a select expression for our example?</p><pre>val channel1: ReceiveChannel = producer1()<br>val channel2: ReceiveChannel = producer2()</pre><pre><strong>select&lt;Unit&gt; {<br>    channel1.onReceive {<br>        println(it)<br>    }<br>    channel2.onReceive {<br>        println(it)<br>    }<br>}</strong></pre><p>Inside the select expression’s lambda, I am calling the <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/on-receive.html">onReceive</a> <em>clause</em> on both Channels. This clause can only be used from inside a select expression. Therefore, I am listening to emissions on both of these Channels <em>simultaneously</em>. The first value received from either Channel will be printed to the console.</p><p>Here is a full example that you could play with.</p><pre>fun main() = runBlocking {<br>    <br>    val channel1 = producer1()<br>    val channel2 = producer2()</pre><pre>    repeat(10) {<br>        <strong>select</strong>&lt;Unit&gt; {<br>            <strong>channel1</strong>.<strong>onReceive</strong> {<br>                println(it)<br>            }<br>            <strong>channel2</strong>.<strong>onReceive</strong> {<br>                println(it)<br>            }<br>        }<br>    }</pre><pre>    coroutineContext.cancelChildren()<br>}</pre><pre>fun CoroutineScope.producer1() = produce&lt;String&gt; {<br>    while (true) {<br>        delay(1000)<br>        send(&quot;Producer Item 1&quot;)<br>    }<br>}</pre><pre>fun CoroutineScope.producer2() = produce&lt;String&gt; {<br>    while (true) {<br>        delay(2000)<br>        send(&quot;Producer Item 2&quot;)<br>    }<br>}</pre><p>If you run this example, you will see that each execution of the select expression produces a new value that could be from either Channel.</p><h3>Flow Combine Implementation</h3><p>Under the hood, the combine operator uses a select expression to listen to emissions from multiple Flows. Let’s look closely at the source to understand the implementation. Here is a diagram showing how it works.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tRVzWFGly3pSJ7so5YwVjA.png" /><figcaption>Flow Combine Implementation</figcaption></figure><p>Suppose we want to combine Flow A and Flow B.</p><ol><li>Two producer coroutines are created for Flow A and Flow B.</li><li>A select expression is created to listen to the emission of both producers. The select expression runs until a value is received from both producers’ channels. These values emitted from both Flows are stored locally in variables.</li><li>When emissions are received from both producers, they are combined with the transformation that you specify.</li><li>Finally, the transformed value is given back to you in a new Flow that you could collect from.</li></ol><p>These are the steps that are taken when you use the combine operator. Here is the source for these steps.</p><pre>suspend fun &lt;T1, T2, R&gt; FlowCollector&lt;R&gt;.combineTransformInternal(<br>    first: Flow&lt;T1&gt;, second: Flow&lt;T2&gt;,<br>    transform: suspend FlowCollector&lt;R&gt;.(a: T1, b: T2) -&gt; Unit<br>) {<br>    <em>coroutineScope </em>{<strong><br>        </strong>val firstChannel = <em>asFairChannel</em>(first)<br>        val secondChannel = <em>asFairChannel</em>(second)</pre><pre>        var firstValue: Any? = null<br>        var secondValue: Any? = null</pre><pre>        var firstIsClosed = false<br>        var secondIsClosed = false<br>        while (!firstIsClosed || !secondIsClosed) {</pre><pre>            <em>select</em>&lt;Unit&gt; {<strong><br>                </strong><em>onReceive</em>(<br>                    firstIsClosed, <br>                    firstChannel, <br>                    {<strong> </strong>firstIsClosed = true }<strong><br>                </strong>) {<strong> </strong>value <strong>-&gt;<br>                    </strong>firstValue = value<br>                    if (secondValue !== null) {<br>                        transform(...)<br>                    }<br>                }<strong><br><br>                </strong><em>onReceive</em>(<br>                    secondIsClosed, <br>                    secondChannel, <br>                    {<strong> </strong>secondIsClosed = true }<br>                ) {<strong> </strong>value <strong>-&gt;<br>                    </strong>secondValue = value<br>                    if (firstValue !== null) {<br>                        transform(...)<br>                    }<br>                }<strong><br>            </strong>}<strong><br>        </strong>}<br>    }<strong><br></strong>}</pre><p>Source: <a href="https://github.com/Kotlin/kotlinx.coroutines/blob/master/kotlinx-coroutines-core/common/src/flow/internal/Combine.kt">Combine.kt</a></p><p>Let breakdown this source to see the steps in action.</p><pre>suspend fun &lt;T1, T2, R&gt; FlowCollector&lt;R&gt;.combineTransformInternal(<br><strong>    first: Flow&lt;T1&gt;, second: Flow&lt;T2&gt;,<br>    transform: suspend FlowCollector&lt;R&gt;.(a: T1, b: T2) -&gt; Unit<br></strong>) {<br><strong><br></strong>}</pre><p>This function is internal and private. It takes in two Flows and a transformation that you want to apply.</p><ol><li>Two producer coroutines are created for Flow A and Flow B.</li></ol><pre>suspend fun &lt;T1, T2, R&gt; FlowCollector&lt;R&gt;.combineTransformInternal(<br>    first: Flow&lt;T1&gt;, second: Flow&lt;T2&gt;,<br>    transform: suspend FlowCollector&lt;R&gt;.(a: T1, b: T2) -&gt; Unit<br>) {<br>    <em>coroutineScope </em>{<strong><br>        val firstChannel = <em>asFairChannel</em>(first)<br>        val secondChannel = <em>asFairChannel</em>(second)</strong></pre><pre>    }<br>}</pre><pre>fun CoroutineScope.asFairChannel(<br>       flow: Flow&lt;*&gt;<br>): <strong>ReceiveChannel</strong>&lt;Any&gt; = <strong><em>produce</em></strong><em> </em><strong>{<br>    </strong>val channel = channel as ChannelCoroutine&lt;Any&gt;<br>    flow.<em>collect </em><strong>{ </strong>value <strong>-&gt;<br>        </strong>return@collect channel.sendFair(value ?: <em>NULL</em>)<br>    <strong>}<br>}</strong></pre><p>A coroutine is created using the produce coroutine builder. It provides you with a Channel that you could send values emitted from a Flow. This is what the asFairChannel method is doing.</p><p>2. A select expression is created to listen to the emission of both producers.</p><pre>suspend fun &lt;T1, T2, R&gt; FlowCollector&lt;R&gt;.combineTransformInternal(<br>    first: Flow&lt;T1&gt;, second: Flow&lt;T2&gt;,<br>    transform: suspend FlowCollector&lt;R&gt;.(a: T1, b: T2) -&gt; Unit<br>) {<br>    <em>coroutineScope </em>{<strong><br>        </strong>val firstChannel = <em>asFairChannel</em>(first)<br>        val secondChannel = <em>asFairChannel</em>(second)</pre><pre><strong>        var firstValue: Any? = null<br>        var secondValue: Any? = null</strong></pre><pre><strong>        var firstIsClosed = false<br>        var secondIsClosed = false<br></strong>}</pre><p>For each channel we store it’s emission into a variable and maintain whether it’s closed with a flag.</p><pre>suspend fun &lt;T1, T2, R&gt; FlowCollector&lt;R&gt;.combineTransformInternal(<br>    first: Flow&lt;T1&gt;, second: Flow&lt;T2&gt;,<br>    transform: suspend FlowCollector&lt;R&gt;.(a: T1, b: T2) -&gt; Unit<br>) {<br>    <em>coroutineScope </em>{</pre><pre><strong>        </strong>val firstChannel = <em>asFairChannel</em>(first)<br>        val secondChannel = <em>asFairChannel</em>(second)</pre><pre>        var firstValue: Any? = null<br>        var secondValue: Any? = null</pre><pre>        var firstIsClosed = false<br>        var secondIsClosed = false</pre><pre>        <strong>while (!firstIsClosed || !secondIsClosed) {</strong><br>            <strong><em>select</em>&lt;Unit&gt; {<br>              </strong>...<strong><br>            }  <br>        }              </strong><br>    }<strong><br></strong>}</pre><p>Why is the select expression above in a while loop?</p><p>So, let’s recall the simple example we looked at for a select expression. You will find that it completes execution when one of the Channels you are listening to emits a value. Depending on the rate of the emissions from the Channels, you may get value from either the first or second Channel in any order. Therefore, we have variables firstValue and secondValue to store the emitted value. Since we need the first emission from both Channels, the select expression is run until either Channel is closed to ensure we read from both Channels.</p><p>3. When items are received from both producers, they are combined with the transformation that you specify.</p><pre>while (!firstIsClosed || !secondIsClosed) {<br><em>      select</em>&lt;Unit&gt; {<strong><br>          <em>onReceive</em>(...) { value -&gt;<br>              firstValue = value<br>               if (secondValue !== null) {<br>                   transform(...)<br>               }<br>           }<br><br>           <em>onReceive</em>(...) { value -&gt;<br>               secondValue = value<br>               if (firstValue !== null) {<br>                        transform(...)<br>               }<br>            }<br>        </strong>}<br>    }<strong><br></strong>}</pre><pre>fun SelectBuilder&lt;Unit&gt;.onReceive(<br>    ...,<br>    <strong>channel: ReceiveChannel&lt;Any&gt;</strong>,<br>    ...,<br>    <strong>onReceive: suspend (value: Any) -&gt; Unit</strong><br>) {<br>    if (isClosed) return<br>    <strong>channel.onReceiveOrNull</strong> {<strong><br></strong>        if (it<strong> </strong>=== null) onClosed()<br>        else onReceive(<strong>it</strong>)<br>    <strong>}<br></strong>}</pre><p>How are values read in from the Channels in the select expression?</p><p>onReceiveOrNull is a select <em>clause</em> on Channel. It is being used to read the value emission from the channel above in the onReceive. If there are no more emissions from the Flow, the channel is closed. The emitted values are stored in the variables firstValue and secondValue. These values are used to apply the transformation you had specified.</p><p>4. Finally, the transformed value is given back to you in a new Flow that you could collect from.</p><pre>fun &lt;T1, T2, R&gt; Flow&lt;T1&gt;.combine(<br>   flow: Flow&lt;T2&gt;, <br>   transform: suspend (a: T1, b: T2) -&gt; R<br>): Flow&lt;R&gt; = <strong><em>flow </em>{<br>    <em>combineTransformInternal</em>(this@combine, flow) { a, b -&gt;<br>        emit(transform(a, b))<br>    }<br>}</strong></pre><p>Source: <a href="https://github.com/Kotlin/kotlinx.coroutines/blob/master/kotlinx-coroutines-core/common/src/flow/operators/Zip.kt">Zip.kt</a></p><p>As you could see in the code snippet above, the combine operator calling the internal method I showed above. It creates a new Flow and emits the transformed values.</p><p>This is how the combine operator uses select expressions internally. Although they are experimental, when you look under the hood, they are used in many places. Furthermore, the combine operator is very useful in many use cases such as implementing an MVI architecture. Understanding how combine works internally is valuable when debugging and testing.</p><p>I hope this article was helpful. If you have any questions, feel free to respond to this article.</p><p><em>Find me on Twitter.<br></em><a href="https://twitter.com/heyitsmohit"><em>https://twitter.com/heyitsmohit</em></a></p><p><em>Slides from my presentations on Channels &amp; Flows<br></em><a href="https://speakerdeck.com/heyitsmohit"><em>https://speakerdeck.com/heyitsmohit</em></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cbe419ba515f" width="1" height="1" alt=""><hr><p><a href="https://proandroiddev.com/combining-kotlin-flows-with-select-expressions-cbe419ba515f">Combining Kotlin Flows with Select Expressions</a> was originally published in <a href="https://proandroiddev.com/">ProAndroidDev</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Kotlin Flow Assert Delight]]></title>
            <link>https://proandroiddev.com/kotlin-flow-assert-ff45465c01c0?source=rss-9057ae5f9de4------2</link>
            <guid isPermaLink="false">https://medium.com/p/ff45465c01c0</guid>
            <category><![CDATA[kotlin]]></category>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[kotlin-coroutines]]></category>
            <dc:creator><![CDATA[Mohit Sarveiya]]></dc:creator>
            <pubDate>Tue, 18 Feb 2020 02:54:51 GMT</pubDate>
            <atom:updated>2020-02-23T23:55:20.331Z</atom:updated>
            <content:encoded><![CDATA[<p>How do we assert items are being emitted from a <a href="https://kotlinlang.org/docs/reference/coroutines/flow.html">Flow</a>? We could use <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/collect.html">collect</a>, <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/single.html">single</a>, <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/to-list.html">toList</a> extensions on a Flow. But, I found a nice pattern used in the<a href="https://github.com/cashapp/sqldelight"> SQL Delight library</a> for Flow assertions. In this article, I will describe how this pattern works.</p><p><strong>Use Case</strong></p><p>Let’s look at a simple example we could write a test for. The snippet below shows a repository that takes in an API service. The getUserDetails method uses the service to make a request to get UserDetails. The data is returned in a Flow. The example doesn’t have to be implemented with a Flow. However, for the sake of illustrating testing a Flow, I choose the simplest example possible.</p><pre>class UsersRepository(private val apiService: ApiService) {<br><br>    fun getUserDetails(id: Int): Flow&lt;UserDetails&gt; {<br>        return flow<em> </em>{<strong><br>            </strong>val userDetails = apiService.userDetails(id)<br>            emit(userDetails)<br>        }<strong><br>    </strong>}<br>}</pre><p><strong>Test</strong></p><p>Let’s write a test for this example. We want to test the Flow emits a UserDetails object.</p><pre>@Test<br>fun `should get user details`() = <em>runBlocking </em>{</pre><pre><strong>    </strong>val userDetails = UserDetails(<br>         id = 1,<br>         name = &quot;User 1&quot;,<br>         address = &quot;SF&quot;<br>    )</pre><pre>    // Mock API Service<br>    val apiService = <em>mock</em>&lt;ApiService&gt;() {<strong><br>        </strong>onBlocking {<strong> </strong>userDetails(id = 1) }<strong> </strong><em>doReturn </em>userDetails<br>    }<strong><br>    </strong>val repository = UsersRepository(apiService)</pre><pre>    // Test &amp; Verify<br>    val flow: Flow&lt;UserDetails&gt; = repository.getUserDetails(1)<br>    flow.collect { data -&gt;<br>        data shouldBeEqualTo userDetails<br>    }<br>}</pre><p>I am creating a coroutine using the runBlocking method to run our test in. I have broken down this test into three steps which are mock, test and verify.</p><p><strong>Mocking</strong></p><pre>val userDetails = UserDetails(<br>         id = 1,<br>         name = &quot;User 1&quot;,<br>         address = &quot;SF&quot;<br>    )</pre><pre>// Mock API Service<br>val apiService = <em>mock</em>&lt;ApiService&gt;() {<strong><br>    </strong>onBlocking {<strong> </strong>userDetails(id = 1) }<strong> </strong><em>doReturn </em>userDetails<br>}</pre><p>I am using <a href="https://github.com/nhaarman/mockito-kotlin">mockito-kotlin</a> that provides a lot of helpers for mocking and verifying. Using mock&lt;ApiService&gt;, I am mocking the API service and stubbing out theuserDetails method to return the UserDetails object. <br>The userDetails method is suspending. Mockito-Kotlin provides a method calledonBlocking that starts a coroutine using runBlocking and stubs the method for you.</p><p><strong>Testing &amp; Assertion</strong></p><pre>val repository = UsersRepository(apiService)</pre><pre>val flow: Flow&lt;UserDetails&gt; = repository.getUserDetails(1)<br>flow.collect { data -&gt;<br>    data shouldBeEqualTo userDetails<br>}</pre><p>I am injecting the mocked API service into the repository and get the Flow by calling getUserDetails. I am collecting from the Flow and verifying the emission. I could also use the single extension on a Flow for this test.</p><p>This is a simple test. Let’s look at how we could perform the assertion on a Flow in a different way. The <a href="https://github.com/cashapp/sqldelight">SQL Delight library </a>has an extension on a Flow called <a href="https://github.com/cashapp/sqldelight/blob/master/extensions/coroutines-extensions/src/commonTest/kotlin/com/squareup/sqldelight/runtime/coroutines/FlowAssert.kt#L28">test</a>. It gives you an API to collect items, errors and verify that nothing else has been emitted from your Flow. Although, it is not a standalone library current. It&#39;s a nice pattern to follow.</p><p><strong>Flow Assert</strong></p><p>Here is a diagram of how the <a href="https://github.com/cashapp/sqldelight/blob/master/extensions/coroutines-extensions/src/commonTest/kotlin/com/squareup/sqldelight/runtime/coroutines/FlowAssert.kt#L28">test</a> extension works.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*K_4QE64x30YEtxWuqnmgRQ.png" /></figure><p>All the emissions from the flow you are testing a stored in an unlimited buffered Channel. An API is provided to you to query the channel in the test extension. You could query that there are no more emissions or an error was thrown.</p><p>Let’s look at the test extension implementation. Don’t worry about having to understand it all. I’m going to take you through it piece by piece</p><pre>suspend fun &lt;T&gt; Flow&lt;T&gt;.test(<br>         timeoutMs: Long = 1000L, <br>         validate: suspend FlowAssert&lt;T&gt;.() -&gt; Unit<br>) {<br>    <em>coroutineScope </em>{<strong><br>        </strong>val events = <em>Channel</em>&lt;Event&lt;T&gt;&gt;(<em>UNLIMITED</em>)<br>        val collectJob = <em>launch </em>{<strong><br>            </strong>val terminalEvent = try {<br>                <em>collect </em><strong>{ </strong>item -&gt;<strong><br>                    </strong>events.send(Event.Item(item))<br>                }<strong><br>                </strong>Event.Complete<br>            } catch (_: CancellationException) {<br>                null<br>            } catch (t: Throwable) {<br>                Event.Error(t)<br>            }<br>            if (terminalEvent != null) {<br>                events.send(terminalEvent)<br>            }<br>            events.close()<br>        }<strong><br>        </strong>val flowAssert = FlowAssert(events, collectJob, timeoutMs)<br>        val ensureConsumed = try {<br>            flowAssert.validate()<br>            true<br>        } catch (e: CancellationException) {<br>            if (e !== <em>ignoreRemainingEventsException</em>) {<br>                throw e<br>            }<br>            false<br>        }<br>        if (ensureConsumed) {<br>            flowAssert.expectNoMoreEvents()<br>        }<br>    }<strong><br></strong>}</pre><pre>internal sealed class Event&lt;out T&gt; {<br>    object Complete : Event&lt;Nothing&gt;()<br>    data class Error(val throwable: Throwable) : Event&lt;Nothing&gt;()<br>    data class Item&lt;T&gt;(val item: T) : Event&lt;T&gt;()<br>}</pre><p>Source: <a href="https://github.com/cashapp/sqldelight/blob/master/extensions/coroutines-extensions/src/commonTest/kotlin/com/squareup/sqldelight/runtime/coroutines/FlowAssert.kt#L28">Flow Assert</a></p><ul><li>The test extension is creating a coroutine with coroutineScope builder. The builder creates a coroutine that inherits the context of the parent coroutine.</li></ul><pre>suspend fun &lt;T&gt; Flow&lt;T&gt;.test(<br>         timeoutMs: Long = 1000L, <br>         validate: suspend FlowAssert&lt;T&gt;.() -&gt; Unit<br>) {<br>    <em>coroutineScope </em>{</pre><pre>    }</pre><ul><li>Inside this coroutine with <em>Channel</em>&lt;Event&lt;T&gt;&gt;(<em>UNLIMITED</em>), we declare an unlimited buffered channel to store all the emissions. The type of stored items in this channel is an Event type which is a sealed class. This specifies whether an item was emitted, an error occurred or emission is complete.</li></ul><pre>suspend fun &lt;T&gt; Flow&lt;T&gt;.test(<br>         timeoutMs: Long = 1000L, <br>         validate: suspend FlowAssert&lt;T&gt;.() -&gt; Unit<br>) {<br>    <em>coroutineScope </em>{<br><strong>        </strong>val events = <em>Channel</em>&lt;Event&lt;T&gt;&gt;(<em>UNLIMITED</em>)</pre><pre>    }</pre><pre>}</pre><pre>internal sealed class Event&lt;out T&gt; {<br>    object Complete : Event&lt;Nothing&gt;()<br>    data class Error(val throwable: Throwable) : Event&lt;Nothing&gt;()<br>    data class Item&lt;T&gt;(val item: T) : Event&lt;T&gt;()<br>}</pre><ul><li>A child coroutine is launched in the coroutineScope builder. In this coroutine, the flow is collected. If an item is emitted, it is sent to the channel. As this is an unlimited channel, the coroutine will not suspend itself when the send method is called. If an exception is thrown, it is caught and an error event is sent to the channel. After the collection, the channel is closed.</li></ul><pre>  val collectJob = <em>launch </em>{<strong><br>     </strong>val terminalEvent = try {<br>         <em>collect </em>{<strong> </strong>item -&gt;<strong><br>            </strong>events.send(Event.Item(item))<br>         }<strong><br>         </strong>Event.Complete<br>       } catch (_: CancellationException) {<br>            null<br>       } catch (t: Throwable) {<br>           Event.Error(t)<br>       }<br>       if (terminalEvent != null) {<br>         events.send(terminalEvent)<br>       }<br>       events.close()<br> }</pre><ul><li>After the Flow is collected, an instance of the FlowAssert is created. This is also the receiver of the lambda param of the test extension FlowAssert&lt;T&gt;.() -&gt; Unit. This class provides an API to query the channel.</li></ul><pre>val flowAssert = FlowAssert(events, collectJob, timeoutMs)</pre><p>Here are some of the methods the FlowAssert implements.</p><pre>class FlowAssert&lt;T&gt; internal constructor(<br>    private val events: Channel&lt;Event&lt;T&gt;&gt;,<br>    private val collectJob: Job,<br>    private val timeoutMs: Long<br>) {<br>    </pre><pre>    ...</pre><pre>    suspend fun expectItem(): T {<br>        val event = withTimeout <strong>{<br>            </strong>events.receive()<br>        <strong>}<br>        </strong>if (event !is Event.Item&lt;T&gt;) {<br>            throw AssertionError(&quot;Expected item but was $event&quot;)<br>        }<br>        return event.item<br>    }<br><br>    suspend fun expectComplete() {<br>        val event = withTimeout <strong>{<br>            </strong>events.receive()<br>        <strong>}<br>        </strong>if (event != Event.Complete) {<br>            throw AssertionError(&quot;Expected complete but was $event&quot;)<br>        }<br>    }<br><br>    suspend fun expectError(): Throwable {<br>        val event = withTimeout <strong>{<br>            </strong>events.receive()<br>        <strong>}<br>        </strong>if (event !is Event.Error) {<br>            throw AssertionError(&quot;Expected error but was $event&quot;)<br>        }<br>        return event.throwable<br>    }<br>}</pre><p>Source: <a href="https://github.com/cashapp/sqldelight/blob/master/extensions/coroutines-extensions/src/commonTest/kotlin/com/squareup/sqldelight/runtime/coroutines/FlowAssert.kt#L28">Flow Assert</a></p><p>Each method above is querying the events channel by calling the receive method on it. These methods could be used inside the test extension. This is an overview of how the test extension works. It&#39;s a good pattern used in the SQL Delight library.</p><p><strong>Usage</strong></p><p>How do we modify our example I showed earlier to use this extension?</p><pre>@Test<br>fun `should get user details`() = <em>runBlocking </em>{</pre><pre>     val userDetails = UserDetails(<br>             id = 1, <br>             userName = &quot;User 1&quot;, <br>             city = &quot;SF&quot;<br>    )</pre><pre>    // Mock API Service<br>    val apiService = <em>mock</em>&lt;ApiService&gt;() {<strong><br>        </strong>onBlocking {<strong> </strong>userDetails(id = 1) }<strong> </strong><em>doReturn </em>userDetails<br>    }<strong><br>    </strong>val repository = UsersRepository(apiService)</pre><pre>     // Test &amp; Verify<br>    val flow: Flow&lt;UserDetails&gt; = repository.getUserDetails(1) <br>    flow.test {<br>        assertEquals(expectItem(), userDetails)<br>        expectComplete()<br>    }<br>}</pre><p>I am getting an emission with expectItem and performing an assertion. The expectComplete method ensures there were no more emissions.</p><p>How about testing errors? Let’s write a test for it.</p><pre>@Test<br>fun `should throw error`() = <em>runBlocking </em>{<strong><br>   <br>    </strong>// Mock<br>    val apiService = <em>mock</em>&lt;ApiService&gt;()<br>    <em>whenever</em>(apiService.userDetails()) <em>doAnswer </em>{<strong><br>        </strong>throw IOException()<br>    }</pre><pre><strong>    </strong>// Test and Verify <strong><br>    </strong>val repository = UsersRepository(apiService)<br>    val flow: Flow&lt;UserDetails&gt; = repository.getUserDetails()<br><br>    flow.<em>test </em>{<strong><br>        </strong>assertThat(<br>            expectError(),     <br>            instanceOf(IOException::class.<em>java</em>)<br>        )<br>    }<strong><br></strong>}</pre><p>In the test above, I have mocked the API service to throw an IOException when theuserDetails method is called.</p><pre>// Mock<br>val apiService = <em>mock</em>&lt;ApiService&gt;()<br><em>whenever</em>(apiService.userDetails()) <em>doAnswer </em>{<strong><br>     </strong>throw IOException()<br>}</pre><p>When I call collect from the Flow, it will throw the exception and FlowAssert will catch it and add it as an event to its internal channel. I am querying the channel with the expectError method to verify an error was thrown.</p><pre>// Test and Verify <strong><br></strong>val repository = UsersRepository(apiService)<br>val flow: Flow&lt;UserDetails&gt; = repository.getUserDetails()<br><br>flow.<em>test </em>{<strong><br>   </strong>assertThat(<br>       expectError(),     <br>       instanceOf(IOException::class.<em>java</em>)<br>   )<br>}</pre><p>This is a pattern used in the SQL Delight library for Flow assertions. This test extension is not in a standalone library yet. There are improvements that could be made. But, there is an <a href="https://github.com/cashapp/sqldelight/issues/1416">open issue</a> for it. Please contribute if you would like to do so.</p><p>If you have any issues and corrections, please let me know. Thanks for reading!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ff45465c01c0" width="1" height="1" alt=""><hr><p><a href="https://proandroiddev.com/kotlin-flow-assert-ff45465c01c0">Kotlin Flow Assert Delight</a> was originally published in <a href="https://proandroiddev.com/">ProAndroidDev</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Kotlin Coroutine Channels: Under the Hood Part 1]]></title>
            <link>https://medium.com/@heyitsmohit/kotlin-coroutine-channels-under-the-hood-part-1-6b17de397fe5?source=rss-9057ae5f9de4------2</link>
            <guid isPermaLink="false">https://medium.com/p/6b17de397fe5</guid>
            <category><![CDATA[kotlin]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[kotlin-coroutines]]></category>
            <dc:creator><![CDATA[Mohit Sarveiya]]></dc:creator>
            <pubDate>Wed, 22 Jan 2020 02:32:22 GMT</pubDate>
            <atom:updated>2020-04-04T01:13:07.011Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZlWczeyF94SzRxixDyye_Q.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@ludovicolovi?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Ludovico Lovisetto</a> on <a href="https://unsplash.com/s/photos/channel?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>The Kotlin coroutine library provides a construct called a <a href="https://kotlinlang.org/docs/reference/coroutines/channels.html">Channel</a> which behaves like a <a href="https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html">BlockingQueue</a>. How do Channels work underneath the hood? That’s what we’ll explore in this blog series. As you create complex use cases, it will involve building producers with Channels. Understanding how Channels work will help you to debug your code. Let’s dive into Channels.</p><p><strong>What is a Channel?</strong></p><p>A Channel is a construct that allows you to send and receive values. It has an optional buffer to cache the values.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FjEP1eWqm8i4NQ8eVpNp8A.png" /></figure><p>It is implemented as an interface that has two suspending methods — send and receive. There are five types of Channels</p><ul><li>Rendezvous Channel</li><li>Buffered Channel</li><li>Unbuffered Channel</li><li>Conflated Channel</li><li>Broadcast Channel</li></ul><p>Each Channel has a distinct property. We will explore the Rendezvous Channel in this blog post as it is the simplest type of Channel.</p><p><strong>Rendezvous Channel</strong></p><p>A Rendezvous Channel has two properties. It doesn’t have a buffer. If you send a value to it, it will wait until there is a receiver to read the value. Let’s look at this behavior with an example.</p><pre><em>runBlocking</em> {<strong><br>    <br>    </strong>val channel = <em>Channel</em>&lt;Int&gt;()</pre><pre><em>    launch </em>{<br>      channel.send(2)<br><strong>    </strong>}<br>}</pre><p>In this example, we have created a Rendezvous channel in the <em>runBlocking</em> coroutine. The child coroutine sends a value of 2. When the send method is called, it will suspend the child coroutine. This is because there is no reciever reading the sent value.</p><p>We could observe this behavior by using <a href="https://github.com/Kotlin/kotlinx.coroutines/tree/master/kotlinx-coroutines-debug">DebugProbes</a>. It allows us to view the state of all the coroutines in our program.</p><pre><em>runBlocking </em>{</pre><pre>    DebugProbes.install()<br>    val channel = <em>Channel</em>&lt;Int&gt;()</pre><pre><em>    launch </em>{<br>       channel.send(2)<br>    }</pre><pre><em>    delay</em>(2000)<br>    DebugProbes.dumpCoroutines()<br>}</pre><pre>Output:<br>Coroutine StandaloneCoroutine{Active, state: SUSPENDED}</pre><p>In this example, we have installed DebugProbes and used the dumpCoroutines method to view the state of the child coroutine. Its state is suspended. When a consumer is ready to read the value, the child coroutine is resumed. The value sent to the channel is not cached in an array buffer. This is the underlying behavior of a Rendezvous channel. Let’s explore this behavior further by inspecting the channel’s state.</p><p><strong>Channel State</strong></p><p>Every channel has state. The state represents whether the channel is empty, a value was sent or a value was buffered. When you create a channel, it initializes a queue. This queue is a doubly linked list.</p><pre>abstract class AbstractSendChannel&lt;E&gt; {</pre><pre>    protected val queue = LockFreeLinkedListHead()</pre><pre>    ...<br>}</pre><pre>class LockFreeLinkedListNode {</pre><pre>    val _next = atomic&lt;Any&gt;(this)<br>    val _prev = atomic&lt;Any&gt;(this)<br>    ...<br>}</pre><p>The implementation of the queue is based on this paper <a href="https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.140.4693&amp;rep=rep1&amp;type=pdf">Lock-Free and Practical Doubly Linked List-Based Deques Using Single-Word Compare-and-Swap</a>. The operations on a Channel are applications of lock free algorithms.</p><p>Each node added to this queue represents a state. Here are some of the nodes that can be added to the queue:</p><ul><li>SendElement</li><li>SendBuffer</li><li>Receive</li><li>Closed</li></ul><p>You could query the state of the Channel at any point of your program. The <em>toString</em> method is overridden in the channel and it returns the number of items in the buffer and the current head node in the queue.</p><pre>class AbstractSendChannel {</pre><pre>   fun toString() = {$queueDebugStateString}$bufferDebugString”<br>}</pre><p>Every channel inherits <a href="https://github.com/Kotlin/kotlinx.coroutines/blob/master/kotlinx-coroutines-core/common/src/channels/AbstractChannel.kt">AbstractSendChannel</a>. As you can see, it provides debugging information in its toString method.</p><pre><em>runBlocking </em>{</pre><pre>   val channel = <em>Channel</em>&lt;Int&gt;()</pre><pre><em>   println</em>(channel)</pre><pre>}</pre><pre>Output:<br>RendezvousChannel{EmptyQueue}</pre><p>The Channel is currently empty. When I send a value to it, the state will be updated by adding a node of type SendQueued.</p><pre><em>runBlocking </em>{</pre><pre>   val channel = <em>Channel</em>&lt;Int&gt;()</pre><pre><em>   launch </em>{<br>      channel.send(1)<br>   }</pre><pre><em>    delay</em>(2000)<br>    <em>println</em>(channel)</pre><pre>    val num = channel.receive()<br>    <em>println</em>(channel)</pre><pre>}</pre><pre>Output:<br>RendezvousChannel{SendQueued}<br>RendezvousChannel{EmptyQueue}</pre><p>After the <em>runBlocking</em> coroutine has read the value, the queue will be updated to be empty again. Querying the Channel is very helpful as you work through examples and learn about Channels.</p><p>Being able to query the Channel’s queue and its buffered items is helpful in debugging. We’ll go more in-depth on the lock-free algorithms in the next blog post. If you have any questions, please feel free to comment below.</p><p><em>Follow me on Twitter: </em><a href="https://twitter.com/heyitsmohit"><em>@heyitsmohit</em></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6b17de397fe5" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Polling with Kotlin Channels & Flows]]></title>
            <link>https://proandroiddev.com/polling-with-kotlin-channels-flows-1a69e94fdfe9?source=rss-9057ae5f9de4------2</link>
            <guid isPermaLink="false">https://medium.com/p/1a69e94fdfe9</guid>
            <category><![CDATA[kotlin]]></category>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[androiddev]]></category>
            <category><![CDATA[kotlin-coroutines]]></category>
            <category><![CDATA[android]]></category>
            <dc:creator><![CDATA[Mohit Sarveiya]]></dc:creator>
            <pubDate>Tue, 21 Jan 2020 01:30:40 GMT</pubDate>
            <atom:updated>2020-03-04T06:35:37.846Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*H6u-kC2QfCzc0rIMOQbSDA.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@eagleboobs?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Elliott Stallion</a> on <a href="https://unsplash.com/s/photos/polling?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>In this article, I will explore how to implement and test polling with Channels and Flow. Prior to reading on, please check out this <a href="https://kotlinlang.org/docs/reference/coroutines/basics.html">article</a> for understanding the basics of coroutines.</p><p><strong>Problem</strong></p><p>Suppose we would like to hit an endpoint every second and gather the data to display it in the UI. This use case fits many contexts such as continuously updating a live feed or updating scores for a sports event. How could we go about implementing this?</p><p><strong>Solution</strong></p><p>The approach we could take is to create a poller that launches a coroutine that delays for a second, makes an API request and returns the data in a hot Flow. We want the polling to start only when there is a subscriber. Let’s dive into the implementation.</p><pre><strong>interface</strong> Poller {</pre><pre>   <strong>fun</strong> poll(delay: Long): Flow&lt;Data&gt;</pre><pre>   <strong>fun</strong> close()</pre><pre>}</pre><p>I have created an interface with a poll and close method. Thepollmethod takes in a delay in milliseconds and returns a Flow for the given data. The close method stops the polling. The advantage of creating this interface is so that you could provide different implementations of polling if needed.</p><p>Let’s begin by creating a coroutine implementation of the poller.</p><pre><strong>class</strong> CoroutinePoller(<br>    val dataRepository: DataRepository,<br>    val dispatcher: CoroutineDispatcher<br>): Poller {<br><br>    <strong>override</strong> <strong>fun</strong> poll(delay: Long): Flow&lt;Data&gt; { ... }<br><br>    <strong>override</strong> <strong>fun</strong> close() { ... }<br><br>}</pre><p>In this class, I am injecting a repository and a Dispatcher into the poller. The repository makes the request and gives us back the data. The purpose of the Dispatcher is to specify the thread pool the polling should occur on. It also allows me to inject a custom dispatcher for testing as we’ll see later.</p><p><strong>Using channelFlow</strong></p><p>In order to implement the actual logic of polling, we need to launch a coroutine that iteratively delays, makes a request and emits data into a stream. We want this process to start when a client has subscribed to the stream. In order to do this, we will use the <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/channel-flow.html">channelFlow</a> method provided by the coroutines library. It launches a coroutine and creates a channel that we could send items to.</p><pre><strong>class</strong> CoroutinePoller(<br>    val repository: DataRepository,<br>    val dispatcher: CoroutineDispatcher<br>): Poller {<br><br>    <strong>override</strong> <strong>fun</strong> poll(delay: Long): Flow&lt;Data&gt; {<br>        return <strong><em>channelFlow</em></strong><em> </em><strong>{<br>            </strong>while (!isClosedForSend) {<br>                val data = repository.getData()<br>                send(data)                 <br>                <em>delay</em>(delay)<br>            }<br>        }.<em>flowOn</em>(dispatcher)<br>    }<br><br>    <strong>override</strong> <strong>fun</strong> close() {<br>        dispatcher.<em>cancel</em>()<br>    }<br><br>}</pre><p>In the poll method above, I am getting the data and sending it to the channel. This occurs on the injected Dispatcher by using the flowOn extension. I have added a polling delay after the request. The delay and request are happening repeatedly until the channel is closed for send. The polling is halted in the close method by invoking cancel on the injected Dispatcher.</p><p><strong>Error Handling</strong></p><p>In this logic, how do we handle errors? We may want to log the error and continue polling. One way to handle this is to return an <a href="https://arrow-kt.io/docs/apidocs/arrow-core-data/arrow.core/-either/">Either</a> type from the getData method. A Either type allows you to represent one of two types. In this case, it is an Exception or Data. <a href="https://github.com/arrow-kt">Arrow</a> is a library that provides many functional data types like Either. It also provides useful extensions on the Either type.</p><pre><strong>class</strong> CoroutinePoller(<br>    val repository: DataRepository,<br>    val dispatcher: CoroutineDispatcher,<br>    val logger: Logger<br>): Poller {<br><br>    <strong>override</strong> <strong>fun</strong> poll(delay: Long): Flow&lt;Data&gt; {<br>        return <em>channelFlow </em>{<strong><br>            </strong>while (!isClosedForSend) {<br>                <em>delay</em>(delay)<br>                val either = repository.getData()<br>                either.fold({ exception -&gt;<br>                    logger.log(“Failed to get data”)<br>                }, {<br>                    send(data)<br>                })<br>            }<br>        }.<em>flowOn</em>(dispatcher)<br>    }</pre><pre>    <strong>override</strong> <strong>fun</strong> close() {<br>        dispatcher.<em>cancel</em>()<br>    }<br><br>}</pre><p>In the poll method, we are using the fold extension on an Either which accepts two lambda parameters. The first lambda is invoked when an error occurs from the API request. We are logging the error in this scenario. In this use case, I am not halting the polling when an error occurs. I want to keep polling and only log the error. The second lambda is invoked when the request was successful. We are sending the data to the channel in this lambda.</p><p><strong>Testing</strong></p><p>In order to test coroutines, you have to set up a test harness. We need to create and launch a coroutine under which our test code could run. A suspend method cannot be called from a regular method. There are two ways to go about setting up a test harness. One way is to use the runBlocking coroutine builder in each of your tests. The other way to test your code is to use the runBlockingTest method. This is provided by the <a href="https://github.com/Kotlin/kotlinx.coroutines/tree/master/kotlinx-coroutines-test">coroutine test library</a>. runBlockingTest is used for testing delays. The library gives you methods such as advanceTimeBy or advanceTimeUntilIdlto control the passage of time. In our use case, we have a delay of 1 second that we want to control.</p><p>Let’s test that our poller emits data every second.</p><pre><strong>class</strong> CoroutinePollerTest {<br><br>    val data = <em>mock</em>&lt;Data&gt;()</pre><pre>    val repository = <em>mock</em>&lt;DataRepository&gt;() <strong>{<br>        <em>onBlocking</em></strong><em> </em><strong>{ </strong>getData()  <strong>} </strong><em>doReturn </em>data<br>    <strong>}</strong></pre><pre><strong>    val testDispatcher =</strong> <strong>TestCoroutineDispatcher</strong>()<br>    val poller = CoroutinePoller(repository, <strong>testDispatcher</strong>)<br><br>    @Test<br>    <strong>fun</strong> `should poll every second`() = <strong><em>runBlockingTest</em></strong><em> </em>{<strong><br>        </strong>val flow = poller.poll(1_000)<br><br>        <em>launch </em><strong>{<br>            </strong>val dataList = flow.<em>take</em>(2).<em>toList</em>()<br>            assertEquals(dataList.size, 2)<br>        <strong>}<br><br>        </strong>testDispatcher.<strong>advanceTimeBy</strong>(2_000)<br><br>        poller.close()<br>    }<strong><br></strong>}</pre><p>In this test, I am controlling the delay in the poller by calling advanceTimeBy on the injected Dispatcher. The advanceTimeBy method advances forward 2 seconds and two data items are emitted by the channelFlow. The test is using the take extension on the flow to only collect 2 items and store it in a list. We perform an assertion on the list’s size.</p><p><strong>Flow Assertions</strong></p><p><a href="https://github.com/ReactiveX/RxJava">RxJava</a> has a useful <a href="http://reactivex.io/RxJava/javadoc/">test</a> method on an Observable. The <a href="https://github.com/cashapp/sqldelight/blob/master/extensions/coroutines-extensions/src/commonMain/kotlin/com/squareup/sqldelight/runtime/coroutines/FlowExtensions.kt">SQLDelight</a> library has a similar convenient test extension on a Flow. It would be very useful if it was in a <a href="https://github.com/cashapp/sqldelight/issues/1416">standalone library</a>. Here is how we would use it:</p><pre><strong>class</strong> CoroutinePollerTest {<br><br>    val data = <em>mock</em>&lt;Data&gt;()</pre><pre>    val repository = <em>mock</em>&lt;DataRepository&gt;() {<strong><br>        </strong><em>onBlocking </em><strong>{ </strong>getData()  <strong>} </strong><em>doReturn </em>data<br>    }</pre><pre>    val testDispatcher = TestCoroutineDispatcher()<br>    val poller = CoroutinePoller(repository, testDispatcher)<br><br>    @Test<br>    <strong>fun</strong> `should poll every second`() = <em>runBlockingTest </em>{<strong><br>        </strong>val flow = poller.poll(1_000)<br><br>        <em>launch </em>{<strong><br>           flow.test {<br>             expectItem() assertEquals data<br>             expectItem() assertEquals data<br>             expectComplete()<br>           }</strong><br>        }<strong><br><br>        </strong>testDispatcher.advanceTimeBy(2_000)<br><br>        poller.close()<br>    }<strong><br></strong>}</pre><p>The test extension on Flow launches a coroutine, collects from the flow, and sends the items to an unlimited channel. The channel’s type is an Event that is a sealed class. It defines whether a value was received from the flow, no more items were sent or an exception occurred. You could query this channel by calling expectItem, expectError and expectComplete methods. It makes your test cleaner to read.</p><p>This is how you could implement polling and add unit tests for it. If you have any questions or suggestions, please feel free to comment below.</p><p><strong>Resources</strong></p><ul><li><a href="https://github.com/Kotlin/kotlinx.coroutines/tree/master/kotlinx-coroutines-test">Kotlin Coroutines Library</a></li><li><a href="https://github.com/cashapp/sqldelight/blob/master/extensions/coroutines-extensions/src/commonTest/kotlin/com/squareup/sqldelight/runtime/coroutines/FlowAssert.kt">Flow Assert</a></li></ul><p><em>Follow me on Twitter<br>twitter.com/@heyitsmohit</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1a69e94fdfe9" width="1" height="1" alt=""><hr><p><a href="https://proandroiddev.com/polling-with-kotlin-channels-flows-1a69e94fdfe9">Polling with Kotlin Channels &amp; Flows</a> was originally published in <a href="https://proandroiddev.com/">ProAndroidDev</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>