Blog Infos
Author
Published
Topics
Published
Topics
Enhancing Your app’s Testability

Testing is an indispensable part of any project. It enables you to deliver your app with confidence, maintaining a high level of stability and quality. However, tests must be conducted effectively and updated whenever changes occur in your code base.

A typical Android Studio project contains two directories for testing based on their execution environment.

  • The test directory contains unit tests, which are faster and local, and can be run on your development machine or a server.
  • The androidTest directory should contain tests that are executed on real or virtual devices. These include integration tests, end-to-end tests, and other tests where the Java Virtual Machine (JVM) alone cannot validate your app’s functionality.

Given a good architecture, these tests can cover a significant part of your application. Typically, all logic will be covered by the unit test and the User Interface (UI) or other untestable functions will be covered by the androidTest.

However, there may be a need for additional testing methods for several reasons. For instance, speed is a factor; a large number of androidTests take a significant amount of time to run. In terms of simplicity, you may need to test a UI that is full of components. There’s also the necessity aspect; it can be challenging to test custom views since the tags are not always easy to apply.

These are the reasons why I sought an alternate solution and found the Screenshot test to be incredibly beneficial.

Screenshot testing involves capturing and comparing snapshots of expected output from a component. It is crucial for validating your app’s appearance and functionality, detecting visual issues, and testing the app as users would use it. It is more efficient than writing numerous assert statements.

If you use Jetpack Compose, screenshot testing allows you to compare previews of your components before and after changes. This makes it easy to test for alterations in texts, padding, style, and anything you can see on your screen.

How to start

I started using screenshot testing with Paparazzi, a very smart library that I encourage you to check out. However, I experienced some problems with it, as it is incompatible with Robolectric and can cause problems when updating Gradle if it is not supported by the library.

Following the Now in Android episode #90, I discovered a new way to do screenshot testing with another library called Roborazzi. It is integrated with Robolectric, which allows you to interact with your components inside the tests.

Let’s start developing! I’ll show you how to integrate and use this library in your existing project (or in a new project, as I’ll do here to show you all the steps in detail).

Configure the project

To add Roborazzi to your project, you need to add the following plugin to your root build.gradle file:

plugins {
   ...
   id ("io.github.takahirom.roborazzi") version "1.7.0-alpha-1" apply false
}

In the module build.gradle:

plugins {
...   
id("io.github.takahirom.roborazzi")
}
android {
   ...
   testOptions.unitTests.isIncludeAndroidResources = true
  
}

You also need to add the following dependencies:

testImplementation("androidx.compose.ui:ui-test-junit4-android")
testImplementation("org.robolectric:robolectric:4.10.3")
testImplementation("io.github.takahirom.roborazzi:roborazzi:1.7.0-alpha-1")
testImplementation("io.github.takahirom.roborazzi:roborazzi-compose:1.7.0-alpha-1")
testImplementation("androidx.test.ext:junit-ktx:1.1.5")
Writing Roborazzi tests

Once you have added Roborazzi to your project, you can start writing Roborazzi tests. Here a simple one:

@RunWith(AndroidJUnit4::class)
@GraphicsMode(GraphicsMode.Mode.NATIVE)
@Config(sdk = [33], qualifiers = RobolectricDeviceQualifiers.Pixel5)
class MainActivityKtTest {

    @get:Rule
    val composeTestRule = createAndroidComposeRule<ComponentActivity>()

    val directoryName = "MainActivityKtTest"

    @Test
    fun testGreeting() {
        composeTestRule.setContent {
            MyTheme {
                Greeting(name = "Test", modifier = Modifier.padding(12.dp))
            }
        }

        composeTestRule.onRoot().captureRoboImage(
            filePath = "src/test/screenshots/$directoryName/greeting.png",
            roborazziOptions = RoborazziOptions(
                recordOptions = 
                  RoborazziOptions.RecordOptions(resizeScale = 0.5)
            )
        )
    }
}

OUR VIDEO RECOMMENDATION

,

Meet Jewel:Create IDE plugins in Compose

Jetpack Compose is the declarative UI toolkit for Android that makes it easy to create beautiful, responsive apps. However, until recently, there was no easy way to use Compose to create IDE plugins without too…
Watch Video

Meet Jewel:Create IDE plugins in Compose

Sebastiano Poggi & Chris Sinco
UX Engineer & UX Design Lead
Google

Meet Jewel:Create IDE plugins in Compose

Sebastiano Poggi & ...
UX Engineer & UX Des ...
Google

Meet Jewel:Create IDE plugins in Compose

Sebastiano Poggi ...
UX Engineer & UX Design L ...
Google

Jobs

No results found.

To take a screenshot of the Compose component, we can use the captureRoboImage() function. This function will take a screenshot of your component and save it to a file.

Running your tests

To run your Roborazzi tests, you can use the following command:

./gradlew recordRoborazziDebug

Following the captureRoboImage() function an image is generate.

This is the golden value, the image that will be used to understand if something is changing.

To demonstrate how to compare the screenshots, I will modify this line of code:

Greeting(name = "Test 2", modifier = Modifier.padding(2.dp))

To verify that your Compose component still looks as expected, you can run the following command:

./gradlew verifyRoborazziDebug

This will compare the current image of your Compose component to the golden image. If the images are different, the test will fail.

In this case we have a failed test. We can locate the comparison image by navigating through the following path: build -> output -> roborazzi. This image will provide a visual representation of the changes that occurred.

You can observe the golden image on the left and the new one on the right, with all the differences displayed in the center.

A notable enhancement involves adding the following lines to the gradle.properties file:

roborazzi.test.compare = true
roborazzi.test.verify = true

This configuration will ensure that the verification process is automatically executed every time you run your tests.

Testing rules

Another notable feature is related to testing rules. By adding the following dependency:

testImplementation("io.github.takahirom.roborazzi:roborazzi-junit-rule:1.7.0-alpha-1")

You gain the ability to write tests in the following manner:

@get:Rule
val composeTestRule = createAndroidComposeRule<ComponentActivity>()

val directoryName = "MainActivityKtTest"

@get:Rule
val roborazziRule = RoborazziRule(    
    composeRule = composeTestRule,
    captureRoot = composeTestRule.onRoot(),    
    options = RoborazziRule.Options(
        captureType = RoborazziRule.CaptureType.LastImage(),        
        outputDirectoryPath = "src/test/screenshots/$directoryName",
        outputFileProvider = { description, outputDirectory, fileExtension ->           
         File(outputDirectory,               
 "${description.methodName}.$fileExtension")      
  } ))

@Test
fun testGreeting() {    
  composeTestRule.setContent {
        MyTheme {           
           Greeting(name = "Test", modifier = Modifier.padding(12.dp))
        }
      }
}

This approach eliminates the need to manually call captureRoboImage() and specify the path each time you run tests.

Additionally, I’d like to mention another feature: the ability to use GIFs for testing animations or interactions. However, I’ve encountered several issues with this feature, so please be careful before incorporating it into your testing workflow.

Conclusions

You’ve seen in this article the basic of screenshot testing and how to integrate and utilize Roborazzi in your projects. This library will help you to increase your coverage and simplify your tests.

I’d love to hear your thoughts on this matter. Please feel free to share your comments below, or if you prefer, you can reach out to me on Twitter or LinkedIn.

Have a great day!

This article was previously published on proandroiddev.com

YOU MAY BE INTERESTED IN

YOU MAY BE INTERESTED IN

blog
Compose is a relatively young technology for writing declarative UI. Many developers don’t even…
READ MORE
blog
When it comes to the contentDescription-attribute, I’ve noticed a couple of things Android devs…
READ MORE
blog
Compose is part of the Jetpack Library released by Android last spring. Create Android…
READ MORE
blog
Welcome to part 5 of “Building a Language Learning App with Compose “ series.…
READ MORE

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.

Menu