[MUSIC PLAYING]
ADARSH FERNANDO: Hi.
I'm Adarsh Fernando, product manager on Android developer
tools.
And in this video, we're going to talk
about how you can make your automated UI tests easier
to write and scale.
Automated testing of your UI is critical in ensuring
that the behavior, look, and feel of your app
provide a consistent and high quality
experience for your users across different devices and form
factors.
But doing it scalably is not without its challenges
so we've been working hard on solutions to help from APIs
that test your app against configuration
changes in a synchronous way and accessing real OEM
devices scalability to official support for fast hosted
screenshot testing.
We've got a lot to talk about so let's jump in.
Device configuration changes, such as rotating device
or unfolding a screen to your app, are a common occurrence.
And without proper testing, users
may discover issues with layouts, persisting data,
or app stability before you do.
So what's the best way to test your app
across these configuration changes?
Well, that's where the new Espresso Device API comes in.
When using Android virtual devices
running API level 24 or higher, this new API
allows you to perform configuration changes
during test execution.
And the best part is it does so in a synchronous way so no more
fiddling around with sleep functions.
Before you get started, you'll need to make sure your project
is using the latest Canary version of Android Gradle
plugin 8.2 and that you've downloaded and installed
Android emulator 33.1.1O or higher from the SDK Manager.
Next, make sure your app grants the internet and access network
state permissions.
This part is necessary for the test
to be able to pass commands to the test device.
Remember you can add this to only the Android test
manifest so it doesn't affect your release version.
Finally, in your app module Gradle file,
set testOptions emulatorAccess enabled to true.
And while you're here, go ahead and import the espresso device
library into your app project.
Now for the fun part.
Let's see how this works with a test that performs
a basic device rotation.
First we want to ensure a consistent starting state
for our device so we create a rule to set
the device to portrait mode.
We can then create a test for what
happens when the screen rotates to landscape.
Before the configuration change is complete,
the test asserts that the UI adapts
to the new layout as expected.
These APIs can help you test rotations
on a number of device form factors.
But there are also capabilities specifically for foldables.
For example, there are foldable devices
such as the Pixel Fold that have a rich outer display, which
can be useful to quickly check a notification or new content.
But if the user wants to engage more deeply into your app,
they might unfold the device to use the larger screen.
Transitioning your app from the outer screen
to the inner screen results in a configuration
change where your app should respond to the increased screen
size.
The device API has a number of foldable states
that you can use to simulate these configuration changes.
First, let's start the test with the device in the folded state
by calling onDevice setClosedMode.
We can then make sure our app's layout has adapted
to the compact screen width.
We can then call onDevice setFlatMode to transition
to a fully unfolded state and assert
whether our layout has adapted to the expanded size class.
Like the other Espresso Device APIs,
this call is fully synchronous.
Because this test performs folding actions,
it's likely to fail on a standard phone or tablet.
Wouldn't it be nice if we could just
skip this test when running on a device that isn't foldable?
Well, the device API has a solution for that, too.
You can specify which of your tests
require a foldable device by using the RequiresDeviceMode
annotation.
Here we've added it to our foldable test function
and specified that we need a device that supports flat mode.
Now when testing multiple form factors,
the test run automatically skips running this test
on devices that don't support unfolding
to a flat configuration.
You can add this rule for each test or an entire test class.
While these APIs currently work only with virtual devices,
physical Pixel devices such as the Pixel fold and Pixel Tablet
announced today will be able to take advantage of these APIs.
But what do you do if you need quick access
to real physical devices to run your tests?
That's where Gradle managed devices' newly
added support for Firebase Test Lab comes in.
Just a quick recap before we get into the new features.
Gradle Managed Devices launched last year
to help make it easy for developers
to use a variety of virtual devices
in both local and CI testing.
With a few lines of configuration in your
build scripts, the Android Gradle plugin
takes care of downloading and creating devices, managing
snapshots and test caches for faster,
more consistent execution, and shutting down devices
to release valuable resources.
And with a new type of virtual device image that
is optimized for lightweight testing
called automated test devices, GMDs
are the recommended way to utilize local virtual devices
in your CI.
But there are times where you really
need to test on real, physical devices.
With built-in experimental support and Gradle Managed
Devices, it's now easier to leverage Firebase Test Lab's
selection of physical and virtual devices
to run your tests from CI.
To get started, we'll first need to import the Firebase Test Lab
plugin into the top level Gradle project
and then set the following flag in the Gradle.properties file.
Now let's configure our first device.
Here we've specified a physical Samsung device
running API level 33.
And a quick pro tip.
If you're using Android Studio and you're
unsure what model IDs and API levels to use,
the IDE can show you compatible values
as autocomplete suggestions.
Now if we want to run tests with Firebase Test Lab,
we're going to need to authenticate
Gradle with a Firebase account.
Great news is that you can skip doing this manually
by passing Gradle a service account JSON file.
If you don't already have one, go
to your app project in the Firebase Console
to download it.
Then just use the following DSL to point Gradle
to its location.
Now we're ready to run the test.
Just use the Android test task with the device name
and build variant you want to test.
Gradle then builds your app, uses your service account
to run your test on Firebase Test lab,
and returns the results right back to your local machine.
The results are viewable in a HTML report, a protofile
you can open in Android Studio, or in the Firebase Console.
Now one device is great for a demo
but we really want to scale with Firebase Test
Lab across multiple devices.
Here I've set up a number of Samsung devices
across different APIs levels and form factors.
We can run tests across all these devices
with a single task by adding them to a device group.
And just as easily, we can run tests
on these devices using the Android test task.
Now keep in mind running a large number of tests
can accumulate a cost so make sure you're
familiar with Firebase's pricing.
Running your test on Firebase Test Lab
is a great way to scale your test
across a number of different form factors
to ensure your app looks great on real devices.
And with Gradle Managed Devices, integrating into your CI
is easier than ever.
But sometimes you just want quick feedback
to check whether a small update to a theme or reusable UI
component created unexpected changes without having
to start up a real device.
Screenshot testing is an effective way
to get visual feedback of recent code changes
across a number of layouts and screen sizes.
They work by comparing screenshots of your app's UI
at a known good state called reference images to those
that were taken during test execution.
If there are no changes, the test passes.
If the test fails, you can either
debug or accept the test screenshot
as the new reference image.
Typically, these tests run on real devices
but what if you could run these tests host
side without building your app and deploying it
to multiple real devices?
Well, if you're already using Compose to write your app's UI,
you're likely familiar with the powerful preview
system in Android Studio, which allows
you to render different components
and layouts across different themes, screen sizes, and UI
states within the IDE.
Coming soon as an experimental feature in Android Gradle
plugin 8.2, we're taking this capability even further
by allowing you to quickly convert these previews to host
side screenshot tests.
Let's say that you just added a new chat screen
to your app built with Compose and set up previews
to show others.
After a few iterations, your tech lead
is happy, your designer is happy, and so is product.
Great.
Now you want to make sure that UI doesn't regress
from the approved design because of changes
in other parts of the app.
So let's set up some screenshot tests
to catch potential regressions early.
To get started, first create a new directory or source
set in your app module and name it screenshotTest.
In that source set, create a Kotlin file
and set up the preview like you normally would.
And that's it.
Now it's time to generate the reference image
by running the ScreenshotTest task with the flag
to record-reference-images.
Gradle generates the reference images
and stores them in your project for you.
You can then commit your reference images along
with your tests to your CI.
Now imagine someone makes a change
to a reusable component that has unintended consequences.
If the change affects your chat screen,
your screenshot test can catch that regression.
Just run the screenshot test task.
After the tests run, Gradle generates a HTML report
that includes the reference image and the new test
image for each failed test.
Can you spot the difference?
If you didn't, that's OK.
The results also provide a diff which
highlights the regions of your app
that are different from the reference image
so you can quickly identify the regression.
And the best part is because this is all
done on the host, tests run much faster than if we needed
to run them on a real device.
So even if you're running these tests on your local machine,
you can test for regressions across many different layouts,
components, screen sizes, and themes
with just a few simple steps.
Remember this feature is heavily experimental so
for the latest behavior changes and instructions on how to get
started, check the preview documentation.
We've covered a lot of different ways
that you can adopt, improve, and scale
testing of your app's UI across a number of configuration
changes and device form factors.
We've talked about how the new Espresso Device
API allows you to test your app running on virtual devices
against common configuration changes such as device
rotations and folding in a reproducible, efficient,
and synchronous way.
And with Gradle managed devices, you
can now easily integrate Firebase Test Lab
into your continuous testing.
With just a few lines in your build script,
you can connect to your existing Firebase project
and leverage Firebase's large selection
of virtual and physical devices to scale
your continuous testing.
And coming soon to Android Gradle plugin
8.2, built-in support for using your Compose
previews for host-side screenshot testing
helps catch potential regressions
in your app's layouts across different themes, screen sizes,
and states.
It'll manage reference images and provide quick results that
are visual and easy to follow.
These experimental features are just
the start for providing more useful ways
to help you write, run, investigate, and scale
your tests so please try them out
and provide feedback to make them even better.
Until next time, thanks for watching.
[MUSIC PLAYING]