Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Devfest 2022 - Advantages of espresso tests aut...

Devfest 2022 - Advantages of espresso tests automation how and why ? by Madona S. Wambua

As engineers, it is good practice to maintain a healthy culture where we write both UI and unit tests. However, the biggest hurdle comes when you have to set up continuous integration; how do you ensure your tests don’t slow down builds from other pull requests hence slowing down the merge process..? What if I told you we found a tool and now run our UI tests nightly and on specific days? Join me, and let’s talk about how, why, and what tool we use.

Madona S. Wambua
Twitter: @madona_syombua
Linkedin: in/madona-syombua/

GDG Montreal

November 19, 2022
Tweet

More Decks by GDG Montreal

Other Decks in Programming

Transcript

  1. AGENDA • What is UI Testing • Android UI Test

    Automation • Flakiness • UI Automator APIs • Popular Android UI Testing Tools • Unit Testing • CI/CD Tools • Conclusion @madona_syombua
  2. About Me • Android Engineer • GDE Android • Author

    • Women Tech Makers Ambassador @madona_syombua
  3. @madona_syombua Pros • Automated software testing can increase the depth

    and scope of tests to help improve software quality. • Lengthy tests that are often avoided during manual testing can be run unattended. • Automated software testing can look inside an application and see memory contents, data tables, file contents, and internal program states to determine if the product is behaving as expected. • Test automation can easily execute thousands of different complex test cases during every test run providing coverage that is impossible with manual tests.
  4. UI Testing Suites 5 Accessibility 4 Visual Design (UX) 3

    Usability Perform ance 2 1 Functionality @madona_syombua
  5. Data Type / Field Length This is ensuring the correct

    data type is entered, e.g Integer instead of strings. Also validating that fields length and ensuring users don’t enter many chars 2 User Actions (End to end) This can vary from start to finish say logging into your account, accessing your profile and more. Navigation 1 3 2 1 Test Cases 3 Progress Bar Good a example includes progress bar, and that is the test verifies that the correct state is sent to the screen @madona_syombua
  6. Jetpack Frameworks 2 Jetpack Compose testing APIs 3 UI Automator

    4 Robolectric 1 Espresso Testing Framework Frameworks that provide APIs for writing UI tests @madona_syombua
  7. @Test fun assertProgressBarIsShownWhenIsLoading() { composeTestRule.setContent { loginContent( state = State(isLoading

    = true), ) } composeTestRule .onNodeWithTag(TestTags.UI.BUTTON_PROGRES S_BAR) .assertIsDisplayed() } Sample Validation @Test fun assertProgressBarIsNotShownWhenIsNotLoadi ng() { composeTestRule.setContent { loginContent( state = State(isLoading = false), ) } composeTestRule .onNodeWithTag(TestTags.UI.BUTTON_PROGRES S_BAR) .assertDoesNotExist() } @madona_syombua
  8. Testing with Rx @Test fun emitsDisconnectingSstateWithRegisteredUser() { val testObserver =

    user.registered.test() registered.exitInProgress.onNext(true) testObserver.awaitCount(2).assertNoTimeout().assertValues( RegisteredUser.NotConnected, ) } @madona_syombua
  9. Use test() method to get a TestObserver you can make

    assertions on. Can do things like: • Await completion • Assert count of values emitted • Assert sequence and items expected • Assert a timeout did / did not happen • Assert an expected error was raised @madona_syombua
  10. class ScreenUnitTestRule<T : Activity>( activityClass: Class<T>, private val navigateToScreen: T.()

    -> Unit, private val setupMocks: () -> Unit = {} ) : ActivityTestRule<T>(activityClass) { @ExperimentalStdlibApi override fun beforeActivityLaunched() { val instrumentation = InstrumentationRegistry.getInstrumentation() (instrumentation.targetContext.applicationContext as App).run { setupMocks() } } override fun afterActivityLaunched() { activity.navigateToScreen() } } Set-up @madona_syombua
  11. Take advantage of long method names in Kotlin @Test fun

    `when users wants to exit, make sure they can exit without holding data’(){ ... } @madona_syombua
  12. Testing Navigation @Test fun testLoginFragmentToHomeFragment() { launchFragmentInHiltContainer<LoginFragment>(null, R.style.CustomTheme) { //

    Create a NavController and set the NavController property on the fragment assertNotNull(requireActivity()) val navController = TestNavHostController(requireActivity()) requireActivity().runOnUiThread { navController.setGraph(R.navigation.nav_login) } Navigation.setViewNavController(requireView(), navController) // Then navigate navController.navigate(R.id.action_loginFragment_to_homeFragment) val destination = navController.currentDestination assertNotNull(destination) assertEquals(destination?.id, R.id.homeFragment) } } @madona_syombua
  13. Click a Button Idling? Assert Success Yes No @madona_syombua Credits:

    https://developer.android.com/training/testing/espresso/idling-resource
  14. Click a Button Click a Button Wait ..Seconds Using Wait/Sleep

    leads to flaky or slow tests @madona_syombua
  15. Write automated tests with UI Automator Instrumentation Based API works

    with AndroidJunitRunner Retrieves state information and perform operation on the target device APIs that support cross app UI testing @madona_syombua
  16. Accessing device state Change the device rotation Press a hardware

    key, such as “volume up” Press the back, home or menu buttons Take a screenshot of the current window 03 01 02 @madona_syombua
  17. device = UiDevice.getInstance(getInstrumentation()) device.pressHome() // Bring up the default launcher

    by searching for a UI component // that matches the content description for the launcher button. val allAppsButton: UIObject = device.findObject( UiSelector().description("Apps")) // Perform a click on the button to load the launcher. allAppsButton.clickAndWaitForNewWindow() @madona_syombua
  18. val cancelButton: UiObject = device.findObject( UiSelector().text("Cancel").className("android.widget.Button") ) val okButton: UiObject

    = device.findObject( UiSelector().text("OK").className("android.widget.Button") ) // Simulate a user-click on the OK button, if found. if (okButton.exists() && okButton.isEnabled) { okButton.click() } @madona_syombua Create a UI Automator test class
  19. fun setUp() { ... val context = getInstrumentation().context val intent

    = context.packageManager.getLaunchIntentForPackage(APP_PACKAGE).apply { addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) } context.startActivity(intent) device.wait(Until.hasObject(By.pkg(APP_PACKAGE).depth(0)), TIMEOUT) } @madona_syombua You can specify a selector
  20. fun testTenPlusSixEqualsSixteen() { // Enter an equation: 10 + 6

    = ? device.findObject(UiSelector().packageName(APP_PACKAGE).resourceId("ten")).click() device.findObject(UiSelector().packageName(APP_PACKAGE).resourceId("plus")).click() device.findObject(UiSelector().packageName(APP_PACKAGE).resourceId("six")).click() device.findObject(UiSelector().packageName(APP_PACKAGE).resourceId("equals")).click() // Verify the result = 16 val result: UiObject2 = device.findObject(By.res(APP_PACKAGE, "result")) assertEquals("16", result.text) } @madona_syombua Now, verify your results
  21. @madona_syombua UI Automator Vs Espresso UI Automator is powerful and

    has good external OS system integration e.g. can turn WiFi on and off and access other settings during test, but lacks backward compatibility as it requires Jelly Bean or higher. Espresso is a bit more light weight compared to UI Automator and supports 2.2 Froyo and up it also has a fluent api with powerful hamcrest integration making code more readable and extensible it is newer than Ui automator. NOTE: UI Automator and Espresso use the same instrumentation runner. credit: https://stackoverflow.com/questions/31076228/android-testing-uiautomator-vs-espresso
  22. Espresso is a famous UI testing framework. It supports android

    applications from 2.3 onwards. It requires access to the source codes. Also, it has a White-box testing feature. Popularly used Espresso @madona_syombua
  23. Some advantages of using Espresso @madona_syombua • Fast and reliable

    testing. • It can test web components • Built-in test Recorder. • Active service and team. • It does testing in such a way that the component is isolated. This makes other activities or components available to work on.
  24. Some disadvantages of using Espresso @madona_syombua • It runs only

    one application at a time. • Test cases can only be for Android. • Test cases are only written in either Java or Kotlin. • Deep understanding required.
  25. Calabash @madona_syombua Calabash is also an open-source and free cross-platform

    UI testing tool. It can work efficiently with .NET, java, ruby, and other languages. It tests the native and hybrid applications.
  26. Monkey is a program that runs on your emulator or

    device and generates pseudo-random streams of user events such as clicks, touches, or gestures, as well as a number of system-level events. You can use the Monkey to stress-test applications that you are developing, in a random yet repeatable manner. Monkey credits : https://developer.android.com/tools/help/emulator @madona_syombua
  27. Use the App Crawler tool, part of Jetpack, to automatically

    test your app without the need to write or maintain any code. The crawler runs alongside your app, automatically issuing actions (tap, swipe, etc.) to explore the state-space of your app. The crawl terminates automatically when there are no more unique actions to perform, the app crashes, or a timeout you designate is reached. App Crawler credits : https://developer.android.com/tools/help/emulator @madona_syombua
  28. • Test small units of code to validate their behavior

    • Promote good design, loose coupling • Avoid fragile codebase, promote sustainable growth of the project @madona_syombua
  29. Some guidelines to strive for: • Don't alter global state

    (or reset it if you must) to avoid flakiness in other tests. • Should not communicate with external systems (fake/mock server calls) this is debatable. • ViewModels can be "pure" unit tests with no Android dependencies (although Robolectric is OK if needed) @madona_syombua
  30. Some guidelines to strive for: • In Unit Testing don't

    test private methods, just public interface, • Code to an interface, not an implementation more flexibility of test doubles vs forced to mock. • Unit tests should run FAST so they can be run frequently & easily @madona_syombua
  31. Bitrise @madona_syombua Bitrise is a Continuous Integration and Delivery (CI/CD)

    Platform as a Service (PaaS) with a main focus on mobile app development (iOS, Android, React Native, Flutter, and so on). https://devcenter.bitrise.io/en/getting-started.html
  32. Test Reports @madona_syombua Test Reports allows you to view all

    your test results in a convenient way. https://devcenter.bitrise.io/en/testing/test-reports.html
  33. Thank You: • Website: https://madonasyombua.com/ • Twitter: madona_syombua • Slide

    : https://madonasyombua.com/advantages-of-espresso-tests-automation-how-and-why/ • Pre-Order my book: amazon.com/author/madona_wambua • Resources: https://developer.android.com/training/testing/other-components/ui-automator • More About Automation: https://smartbear.com/learn/automated-testing • Espresso Cheat Sheet: https://developer.android.com/training/testing/espresso/cheat-sheet