Mocking with Jetpack Compose - stubbing and verification of Composable functions

Overview

Mockposable

A companion to mocking libraries that enables stubbing and verification of functions annotated with @androidx.compose.runtime.Composable.

It currently works on JVM and Android, and integrates with the following mocking libraries:

Why

It may come in handy if you need to stub certain functionality exposed by Compose UI, or if you're using Compose for purposes other than Compose UI, and want to do stubbing within that context.
Here are a couple of example use cases from the integration tests of the project:

  • Paparazzi snapshot tests with stubbed collectIsPressedAsState in order to record and verify the look of pressed UI elements.
    See example here
  • Integration tests of a Composable function or Activity/Fragment in combination with a Molecule-style presenter.
    See example here.

How

The reason why we can't stub or verify @Composable functions in the first place is twofold:

  1. They are only allowed to run in a very particular context, namely in androidx.compose.runtime.Composition.setContent.
  2. The Compose compiler plugin transforms @Composable functions like so:
    @Composable fun composableFun(args)
    ->
    @Composable fun composableFun(args, $composer: Composer, $changed: Int)
    This means that even if we're able to provide a context to stub in, we can't provide matchers for the $composer and $changed arguments (unless we resort to reflection shenanigans), as a result, any stubbing we attempt will fail to be matched because the generated argument values will change.

This is addressed by:

  1. Providing a way to run @Composable functions once for stubbing purposes, this then hooks into the stubbing mechanism of the mocking library that is being integrated with.
  2. A Kotlin compiler plugin that runs after the Compose compiler plugin has done its transformations.
    The plugin transforms calls to @Composable functions within a stubbing context like so:
    composableFunctionCall(args = args, $composer = composer, $changed = changed)
    ->
    composableFunctionCall(args = args, $composer = any<Composer>(), $changed = any<Int>())
    This allows us to stub and verify without caring about the values of $composer and $changed.

This approach is multiplatform friendly by virtue of doing compile time IR-transformations rather than runtime bytecode instrumentation.

Usage

Apply and configure the Gradle plugin:

buildscript {
    repositories {
        mavenCentral()
    }
    
    dependencies {
         classpath 'com.jeppeman.mockposable:mockposable-gradle:0.1'
    }
}

apply plugin: 'com.jeppeman.mockposable'

// This is where you configure what mocking libraries to integrate with
mockposable {
    // You can add one or many, e.g:
    // plugins = ['mockk']
    // plugins = ['mockito']
    // plugins = ['mockk', 'mockito']
    plugins = [...] // plugins = listOf(...) for build.gradle.kts
}

This will apply the Kotlin compiler plugin as well as the relevant runtime dependencies.

Stubbing and verification with MockK

The MockK-companion provides counterparts for the MockK standard API that works with @Composable functions.

mockposable {
    plugins = ['mockk']
}
import com.jeppeman.mockposable.mockk.everyComposable
import com.jeppeman.mockposable.mockk.verifyComposable

interface Dumb {
   @Composable 
   fun dumber(arg: Int): Int
}

@Test
fun `test something`() {
    val dumbMock = mockk<Dumb> {
        everyComposable { dumber(any()) } returns 42
    }

    ...
    
    verifyComposable { dumbMock.dumber(any()) }
}

// Stubbing top level composable functions

@Composable
fun topLevelComposable(): String {
    return "foo"
}

@Test
fun `test something else`() {
    mockkStatic("com.example.MyFilenameKt") // The FQ name of the container class Kotlin creates for the top level function
    everyComposable { topLevelComposable() } returns "bar"
    
    ...
    
    verifyComposable { topLevelComposable() }
    unmockkStatic("com.example.MyFilenameKt") 
}

The full API surface of the MockK-companion comprises the following:

MockK Stub/verification function Composable counterpart
every everyComposable
answers answersComposable
andThenAnswer andThenComposable
verify verifyComposable
verifyAll verifyComposableAll
verifyOrder verifyComposableOrder
verifySequence verifyComposableSequence

Stubbing and verification with Mockito

Mockito-companion. Same as MockK-companion but for Mockito.

mockposable {
    plugins = ['mockito']
}
import com.jeppeman.mockposable.mockito.onComposable
import com.jeppeman.mockposable.mockito.verifyComposable

interface Dumb {
   @Composable 
   fun dumber(arg: Int): Int
}

@Test
fun `test something`() {
    val dumbMock = mock<Dumb> {
        onComposable { dumber(any()) } returns 9
    }

    ...
    
    verifyComposable(dumbMock) { dumber(any()) }
}

The full API surface of the Mockito-companion comprises the following:

Mockito Stub/verification function Composable counterpart
on onComposable
doAnswer doAnswerComposable
verify verifyComposable
You might also like...
Holi is a lightweight Jetpack Compose library of colors, gradients and cool utility functions for all your palette needs!
Holi is a lightweight Jetpack Compose library of colors, gradients and cool utility functions for all your palette needs!

Holi is a lightweight Jetpack Compose library of colors, gradients and cool utility functions for all your palette needs!

This repo is to demonstrate the jetpack compose 's canvas api's usage and creating an icon pack using the basic functions.
This repo is to demonstrate the jetpack compose 's canvas api's usage and creating an icon pack using the basic functions.

Jetpack Compose Canvas API Demo App We all know that Jetpack Compose has now reached the 1.0.0 release milestone. This is a huge change we can say for

Boat - A scoped and composable way to navigate

Boat Boat is an implementation of a scoped, simple and composable way to navigat

Pinocchio is a group of libraries for various common UI components. It could contain Composable, View, and everything related to UI.
Pinocchio is a group of libraries for various common UI components. It could contain Composable, View, and everything related to UI.

Pinocchio Pinocchio is a group of libraries for various common UI components. It could contain Composable, View, and everything related to UI. All UI

Simple composable for rendering transitions between backstacks.
Simple composable for rendering transitions between backstacks.

compose-backstack Simple library for Jetpack Compose for rendering backstacks of screens and animated transitions when the stack changes. It is not a

GlassmorphicColumn @Composable
GlassmorphicColumn @Composable

glassmorphic-composables GlassmorphicColumn @Composable GlassmorphicRow @Composable With Non-Image background Setup Gradle: allprojects { reposito

A simple authentication application using Jetpack compose to illustrate signin and sign up using Mvvm, Kotlin and jetpack compose
A simple authentication application using Jetpack compose to illustrate signin and sign up using Mvvm, Kotlin and jetpack compose

Authentication A simple authentication application using Jetpack compose to illustrate signin and sign up using Mvvm, Kotlin and jetpack compose Scree

Compose-navigation - Set of utils to help with integrating Jetpack Compose and Jetpack's Navigation

Jetpack Compose Navigation Set of utils to help with integrating Jetpack Compose

Jetpack Compose Boids | Flocking Insect ๐Ÿœ. bird or Fish simulation using Jetpack Compose Desktop ๐Ÿš€, using Canvas API ๐ŸŽจ
Jetpack Compose Boids | Flocking Insect ๐Ÿœ. bird or Fish simulation using Jetpack Compose Desktop ๐Ÿš€, using Canvas API ๐ŸŽจ

๐Ÿœ ๐Ÿœ ๐Ÿœ Compose flocking Ants(boids) ๐Ÿœ ๐Ÿœ ๐Ÿœ Jetpack compose Boids | Flocking Insect. bird or Fish simulation using Jetpack Compose Desktop ๐Ÿš€ , usi

Owner
Jesper ร…man
Jesper ร…man
Capturable - ๐Ÿš€Jetpack Compose utility library for capturing Composable content and transforming it into Bitmap Image๐Ÿ–ผ๏ธ

Capturable ?? A Jetpack Compose utility library for converting Composable content into Bitmap image ??๏ธ . Made with โค๏ธ for Android Developers and Comp

Shreyas Patil 494 Dec 29, 2022
a set of Settings like composable items to help android Jetpack Compose developers build complex settings screens

This library provides a set of Settings like composable items to help android Jetpack Compose developers build complex settings screens without all the boilerplate

Bernat Borrรกs Paronella 178 Jan 4, 2023
Jetpack Compose Text composable to show html text from resources

HtmlText Current Compose Version: 1.0.3 Compose HtmlText Text composable to show html text from resources Add to your project Add actual HtmlText libr

Alexander Karkossa 57 Dec 23, 2022
A library that enables Safe Navigation for you Composable destinations when using Jetpack Compose Navigation

A library that enables Safe Navigation for you Composable destinations when using Jetpack Compose Navigation

Roman Levinzon 59 Oct 19, 2022
Kapture - A small library for Jetpack Compose to capture Composable content to Android Bitmap

kapture A small utility library for Jetpack Compose to capture Composable conten

Kaustubh Patange 10 Dec 9, 2022
Flippable - A Jetpack Compose utility library to create flipping Composable views with 2 sides

?? Flippable A Jetpack Compose utility library to create flipping Composable views with 2 sides. Built with โค๏ธŽ by Wajahat Karim and contributors Demo

Wajahat Karim 298 Dec 23, 2022
๐Ÿš€๐Ÿž๐Ÿ’ช Collection of Images, Modifiers, utility functions for Jetpack Compose to expand and enrich displaying, manipulating, scaling, resizing, zooming, and getting cropped ImageBitmap based on selection area

Collection of Images, Modifiers, utility functions for Jetpack Compose to expand and enrich displaying, manipulating, scaling, resizing, zooming, and getting cropped ImageBitmap based on selection area, before/after image to with handle to show partial of both images and more is cooking up

Smart Tool Factory 207 Dec 26, 2022
Sample app that shows how to create a bitmap from a Jetpack composable

Creating Bitmaps From Jetpack Composables This app demonstrates how to create a bitmap from a Jetpack composable without the need to display the compo

Johann Blake 14 Nov 29, 2022
Row Coloumn Box Compose Constraint Layout Modifier.xyz Animator Tween animation MutableState Creating custom composable Corners Canvas LaunchedEffect

Row Coloumn Box Compose Constraint Layout Modifier.xyz Animator Tween animation MutableState Creating custom composable Corners Canvas LaunchedEffect

Shivaraj M Patil 1 Apr 13, 2022
Holi is a lightweight Jetpack Compose library of colors, gradients and cool utility functions for all your palette needs!

Holi A library of colors, gradients and utils built using Jetpack Compose for Android Features A wide collection of colors from different palettes for

Siddhesh Patil 167 Dec 5, 2022