August 11th, 2022

Test Kit Annotations update

Andrei Cirja
Senior Android Software Engineer

Hello Android developers!

We are excited to announce an update for the foldable Test Kit library. Test Kit provides utility methods and classes that help you write instrumented tests for large screen and foldable devices. This update adds annotations which are useful for creating tests for one posture at a time. Now, instead of adding extra code to span an app or simulate a folding feature, you can just add an annotation to set up your tests.

Annotations can be used to configure tests for:

  • single-screen or dual-screen modes
  • specific target devices
  • specific device orientations
  • simulated folding features

The annotation syntax is perfect for simple tests where the device remains in the same state for the entire test. The annotations help keep the test code readable and expressive while enabling you to target specific postures and foldable device states.

Test Kit annotations work on any foldable device that supports Jetpack Window Manager, including Surface Duo.

Example source code showing tests with annotations - copyable source is shown later in the article

Figure 1: Android Studio screenshot showing simple tests that detect the correct text label is showing based on the device orientation set via an annotation

If you need to test complex app flows including changing the device state during the test, you should simulate a folding feature or use swipe gestures in code, which is also covered in our Test Kit documentation.

How to add Test Kit to your project

The Test Kit components are available on Maven Central. To write tests with the annotations feature, include the dependencies that match your layout preferences (Views or Jetpack Compose) to your app’s build.gradle file:

Views

  androidTestImplementation "com.microsoft.device.dualscreen.testing:testing-kotlin:1.0.0-alpha4"
  androidTestImplementation "androidx.test.uiautomator:uiautomator:2.2.0"
  androidTestImplementation "androidx.test.espresso:espresso-core:3.4.0"
  androidTestImplementation "androidx.test:runner:1.4.0"
  androidTestImplementation "androidx.test:rules:1.4.0"

Jetpack Compose

  androidTestImplementation "com.microsoft.device.dualscreen.testing:testing-compose:1.0.0-alpha04"
  androidTestImplementation "androidx.test.uiautomator:uiautomator:2.2.0"
  androidTestImplementation "androidx.compose.ui:ui-test-junit4:1.1.1"

How it works

The core for these annotations is two utility classes: FoldableTestRule and FoldableJunit4ClassRunner.

FoldableTestRule is a custom TestRule that must be used together with Test Kit annotations (@SingleScreenTest, @DualScreenTest, @MockFoldingFeature and @DeviceOrientation). Without this rule, the annotations have no effect.

FoldableJUnit4ClassRunner is a custom AndroidJunit4ClassRunner that validates the parameters for Test Kit annotations, and it is recommended to always use it to make the tests run as intended.

Usage scenarios

This section shows which annotations can be used for different test cases.

Test in single- or dual-screen mode

If you want to run tests in single-screen or dual-screen mode, you should use the @SingleScreenTest or @DualScreenTest annotation together with FoldableTestRule and FoldableJUnit4ClassRunner as shown in the following example:

  @RunWith(FoldableJUnit4ClassRunner::class)
  class TestSample {
      private val activityScenarioRule = activityScenarioRule<MainActivity>()
      private val foldableTestRule = FoldableTestRule()
   
      @get:Rule
      val testRule: TestRule = foldableRuleChain(activityScenarioRule, foldableTestRule)
   
      @Test
      @DualScreenTest
      fun sampleTestMethod() {
      }
  }

You can use these annotations either at the test class level or test method level, but not both at the same time. You can find more about these annotations here: @SingleScreenTest/@DualScreenTest

Test on a specific device

If you want to run tests on specific target devices, you must use @TargetDevices annotation with the desired devices provided by the devices parameter. You can also skip some devices with this annotation using the ignoreDevices parameter, like in the following example:

  @RunWith(FoldableJUnit4ClassRunner::class)
  @TargetDevices(devices = [DeviceModel.SurfaceDuo])
  class TestSample {
      private val activityScenarioRule = activityScenarioRule<MainActivity>()
      private val foldableTestRule = FoldableTestRule()
   
      @get:Rule
      val testRule: TestRule = foldableRuleChain(activityScenarioRule, foldableTestRule)
   
      @Test
      fun sampleTestMethod() { // test will ONLY run on Surface Duo devices
      }
  }

In this sample, all the methods from TestSample class will run only on Surface Duo devices. You can use this annotation also at the test method level, but not in both places at the same time.

If you want to ignore some devices, you can use it like this:

  @RunWith(FoldableJUnit4ClassRunner::class)
  @TargetDevices(ignoreDevices = [DeviceModel.SurfaceDuo])
  class TestSample {
      private val activityScenarioRule = activityScenarioRule<MainActivity>()
      private val foldableTestRule = FoldableTestRule()
   
      @get:Rule
      val testRule: TestRule = foldableRuleChain(activityScenarioRule, foldableTestRule)
   
      @Test
      fun sampleTestMethod() { // test will NOT run on Surface Duo devices
      }
  }

You can find more about this annotation here: @TargetDevices

Test a specific orientation

You can run tests in a specific device orientation with the @DeviceOrientation annotation, or if you want also to run it on a single-screen or dual-screen posture, you can use @SingleScreenTest or @DualScreenTest with the deviceOrientation parameter, like this:

  @RunWith(FoldableJUnit4ClassRunner::class)
  @DeviceOrientation(orientation = UiAutomation.ROTATION_FREEZE_180)
  class TestSample {
      private val activityScenarioRule = activityScenarioRule<MainActivity>()
      private val foldableTestRule = FoldableTestRule()
   
      @get:Rule
      val testRule: TestRule = foldableRuleChain(activityScenarioRule, foldableTestRule)
   
      @Test
      fun sampleTestMethod() { // test is run at 180 degree rotation
      }
  }

  @RunWith(FoldableJUnit4ClassRunner::class)
  @SingleScreenTest(orientation = UiAutomation.ROTATION_FREEZE_180)
  class TestSample {
      private val activityScenarioRule = activityScenarioRule<MainActivity>()
      private val foldableTestRule = FoldableTestRule()
   
      @get:Rule
      val testRule: TestRule = foldableRuleChain(activityScenarioRule, foldableTestRule)
   
      @Test
      fun sampleTestMethod() { // test is run at 180 degree rotation
      }
  }

Test with a simulated folding feature

If you want to run tests with a simulated folding feature, you should use @MockFoldingFeature and provide the windowBounds, center, size, state, or orientation parameter. None of these parameters is required because they have default values, but you can find more info about them here: @MockFoldingFeature

  @RunWith(FoldableJUnit4ClassRunner::class)
  @MockFoldingFeature(
      size = 2, 
      state = FoldingFeatureState.FLAT, 
      orientation = FoldingFeatureOrientation.HORIZONTAL
  )
  class TestSample {
      private val activityScenarioRule = activityScenarioRule<MainActivity>()
      private val foldableTestRule = FoldableTestRule()
   
      @get:Rule
      val testRule: TestRule = foldableRuleChain(activityScenarioRule, foldableTestRule)
   
      @Test
      fun sampleTestMethod() { // test is run with custom folding feature configuration
      }
  }

Samples

To make it easier to understand how to use Test Kit annotations, we added a new SDK sample to our Views library. We’ve also updated our Compose samples to use the new annotations in UI tests.

To see examples of how to use each specific annotation, check out the links below:

Annotation name

Sample code

@SingleScreenTest/@DualScreenTest

SurfaceDuoTestSample.kt

OtherFoldableTestSample.kt

@MockFoldingFeature

MockFoldingFeatureSample.kt

@TargetDevices

TargetDevicesSample.kt

@DeviceOrientation

SurfaceDuoDeviceOrientationSample.kt

OtherFoldableDeviceOrientationSample.kt

Resources and feedback

You can review the documentation for more info. You can also try out our sample and check out all these scenarios.

The source code for the Test Kit is available on GitHub if you’re curious about the implementation or wish to contribute. Also visit the documentation for more information on all the features in the dual-screen library for Kotlin and Java developers.  

Thanks to the team – Bianca Miron, Cesar Valiente and Kristen Halper for their work on this update.   

We’d love to hear from you and how you plan to use the Test Kit library in your apps. Please reach to out using the feedback forum or message us @surfaceduodev on Twitter.   

Finally, please join us for our dual screen developer livestream at 11am (Pacific time) each Friday – mark it in your calendar and check out the archives on YouTube. 

Author

Andrei Cirja
Senior Android Software Engineer

Andrei is an engineer on the Surface Duo Developer Experience team, working on building out the dual-screen SDK for Android developers.

0 comments

Discussion are closed.