قالب وردپرس درنا توس
Home / IOS Development / Espresso Testing and Screen Robots: Getting Started

Espresso Testing and Screen Robots: Getting Started



Testing your app is incredibly important but often overlooked. Sometimes this is because the developer just doesn't know where to start. One place to start is to test your user interface using Espresso tests.

You can re-execute your Espresso test writing using Screen Robots to preserve recurring test code. 19659002] In this tutorial you will learn:

  • Which user interfaces are and why they are important.
  • How to use Espresso to test your user interface.
  • Which screen robots are and how they can be useful. 19659007] Using Espresso

    Espresso is not just a delicious coffee drink, but also a complete testing framework from Google that lets you test the user interface of your Android app. Manual click testing all parts of your app are too slow and boring. With Espresso, you can write automated tests to make sure everything works as expected and regress before they happen.

    You can increase the speed of test writing even more by creating Screen Robots. These are helper features that take care of repetition you may have in tests, such as filling out a form.

    Note : UI tests are different from unit tests. Where user interface tests your app by verifying that the user's condition is consistent with a given set of user interface interactions. A unit test, on the other hand, tends to be smaller tests that control class method outputs or condition based on a set of given inputs. To read more about device tests, check out Android Unit Testing with Mockito.

    Getting Started

    To learn about UI testing, you will write tests for an Emoji Tip Calculator app. This app allows you to enter the sum from the bill, select an emoji that represents how you feel about the service, and get a tip amount along with the sum. You also have the opportunity to round up to the nearest dollar.

    Start by downloading the trial project using the Download materials button at the top or bottom of this tutorial. Open and build the startup project in Android Studio.

    Run the app and try it so you know the expected behavior. Try different dollar amounts, choose different emojis and switch round to nearest dollar switch to see what's going on.

     Screenshot of Emoji Calculator app

    You should write a whole new test file for this tutorial, but it may be helpful to get to know some of the other files. Take a look at MainActivity.kt and activity_main.xml . These define the views and logic of the app.

    Adding dependencies

    By default, a generated Android project contains some Espresso dependencies. Each new project should already include the following dependencies in app / build.gradle :

      androidTestImplementation &roid 39. androidx.test: runner: 1.1.1 & # 39;
    androidTestImplementation & # 39; androidx.test.espresso: espresso kernels: 3.1.1 & # 39;
    

    And a standard test runner:

      testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    

    This should be enough for you to write UI tests, but you want to add more regulatory and truth statement libraries provided by Google to reduce the boiler plate code required in tests. Add the following dependencies to app / build.gradle :

      androidTestImplementation &roid 39. androidx.test: rules: 1.1.1 & # 39;
    androidTestImplementation &roidx.test.ext: truth: 1.1.0 & # 39;
    androidTestImplementation & # 39; androidx.test.ext: June: 1.1.0 & # 39;
    

    Sync your .gradle files after you make the change. You can see a summary of what each test addiction provides in the Google documentation.

    Note : If you do not want to use the AndroidX assistants in your own project, you can still follow this tutorial. You will find the necessary changes when you are not using them in future notes. To understand what has been added, take a look at this blog post.

    Writing Espresso Tests

    First, you need a file to write your tests. To view the actual file structure of the project, switch to the project view by selecting Project from the drop-down menu at the top of the window Project on the left.

     Project structure

    Create a MainActivityTest.kt under app ‣ src ‣ ogroidTest ava java ‣ com ‣ raywenderlich ‣ android ‣ emojicalculator . It is common practice to put your test file in the same package structure as the file you are trying to replace, head with androidTest or test for non-Android tests. This package structure mimics the location of MainActivity.kt as that's what you're testing.

    Place the empty class in your file:

      class MainActivityTest {
    
    }
    
    Note : There is a shortcut in Android Studio to create this class file in this location. Place the cursor on the class declaration for MainActivity press ⌘ + ⇧ + T (or Control + Shift + T on Windows) and select Create New Test .. . . A window will appear to select the test site.

    Create the default value and select OK .

     Create Test dialog

    Then select the androidTest directory and select OK again.
      Test Dialog Dialog

    Finally, before writing tests, you need to add a comment to say what to run the tests with. Add this right above your test class statement.

      @RunWith (AndroidJUnit4 :: class)
    

    Use androidx.test.ext.junit.runners.AndroidJUnit4 when prompted to import AndroidJUnit4 and org.junit.runner.RunWith for to import ] RunWith .

    This tells JUnit to run the tests inside AndroidJUnit4 instead of the runner built into JUnit. AndroidJUnit4 is a test runner running JUnit style tests on Android devices.

    • : When not using the AndroidX helper, you do not need this dependency in app / build.gradle :
       androidTestImplementation &roidx.test.ext: truth: 1.1.0 & # 39;
      

      In addition to removing this addiction, add this TestRule inside MainActivityTest :

        @get: Rule
      choice activityRule = ActivityTestRule (MainActivity :: class.java, false, false)
      

Launch an Activity

When testing your user interface, the first thing you need to do is make sure you can, launch it! A launch test is a great first test and ensures that your app or a particular screen can boot without crashing. It is important!

The test names should be clear, easy to read and should focus on telling what to do. To achieve this, avoid using the word test in your test name.

Write a test that launches MainActivity in your test class:

  @Test
fun appLaunchesSuccessfully () {
ActivityScenario.launch (MainActivity :: class.java)
}

This uses ActivityScenario to start MainActivity . The class ActivityScenario is part of AndroidX and provides APIs to start and run an activity life cycle status for testing. Use the androidx.test.core.app.ActivityScenario package when prompted to import ActivityScenario and org.junit.Test to import Test . The test will automatically fail if the app crashes for some reason.

Note : If you do not use the helpers, replace ActivityScenario.launch () with the following at any time you need to start the activity:

 activityRule.launchActivity (null)

Before running the test, you should turn off animations on your test device. Whether it's an emulator or a physical device you're working on, go to Settings ler Developer Options and set all of the following to by :

  • The animation scale of the window.
  • Transition animation scale.
  • Animator duration scale.

Build and run your test! You can do this one of several ways:

  • Select the green triangle in the gutter on the test file.
  • Right-click the test class declaration or file name in the navigator and select Run & # 39; MainActivityTest & # 39;

    • .
    • Runs ./ gradlew connectedAndroidTest from the command line.
    • Configure a test configuration as described here.

     Trial Start Test ]

    Note : To see what the test looks like when it fails, temporarily put a throw RuntimeException () somewhere in onCreate () by MainActivity . It's good to see your test error. That's how you know it's doing its job. Just make sure you remember to fix it!

    Verify an object on the screen

    Now that you know how to start an activity in a test, you can start adding verifications for what's on the screen.

    There are three classes you need to know about following:

    • ViewMatchers contains methods that Espresso uses to find the display on the screen that it needs to interact.
    • ViewActions contains methods that tell Espresso how to automate your user interface. For example, it contains methods like click () that you can use to tell Espresso to click a button.
    • ViewAssertions contains methods used to check if a view matches a particular set of conditions.

    Add the following test to confirm that when the screen is opened, there is a check amount field:

      @ Test
    funny onLaunchCheckAmountInputIsDisplayed () {
    // 1
    ActivityScenario.launch (MainActivity :: class.java)
    
    // 2
    onView (withId (R.id.inputAmount))
    // 3
    .Check (matches (isDisplayed ()))
    }
    

    Here you:

    1. Start the activity, same as before.
    2. Add a campaign for a display with ID inputAmount .
    3. Verify that the matched view appears on the screen.

    All these methods are part of the package androidx.test.espresso. * so make sure you add the correct import.

    This is a pattern you want to see over and over again

     Two Espresso tests passing

    Note : It is now possible to run your Espresso tests. tests with Robolectric instead of on a device or emulator. While Robolectric is faster, device testing gives you access to more features like sensors and is a more accurate environment. It's also fun to see the test runner take over your device to run the tests. Learn more here.

    Matching views using text

    You can match views of many other things than their ID, such as text. Try this while testing for the Okay button. Add the following test to your test class:

      @Test
    funny onLaunchOkayButtonIsDisplayed () {
    ActivityScenario.launch (MainActivity :: class.java)
    
    onView (withText (R.string.okay))
    .Check (matches (isDisplayed ()))
    }
    

    The main difference here is that you use withText () instead of medId () . You can pass both references to String resources that you did over or String literals to this feature.

    Build and run tests.

     Three Espresso Tests Passing

    Note : You might wonder why emoji is treated here as a text. Emoji is just a graphic representation of one or more Unicode characters, and Unicode is a standard that assigns a unique identifier to characters, symbols, and icons. You can learn more about Unicode and character sets here.

    Deciding which match user should use

    If you have printed it above, you may have noticed many autocompletion options after you wrote "with" by withText () or with () . With so many options, how do you know which one to choose?

    First, look for accuracy and brittleness . Then make sure that what you match can only fit the one view you want to test.

    This can tempt you to be very specific, but you also want to make sure that tests do not break with any slight change to the user interface. For example, what if you match with Strings literally Okay and it is later changed to OK and then changed again to Got it ? You must update the test every time.

    This is why matching use of IDs is very common. When you have an ID set, it is probably the only display on that screen with that ID, unless it's a collection, and it's not likely to change.

    Here's Google's convenient Espresso Cheat Sheet for possible Matchers, Actions and Assertions. 19659010] Note : If you snap through all the Android Studio options, note that there is a Record Espresso Test option. Yes, you can use this to automatically create Espresso tests by clicking through your app and entering details into a wizard.

    However, the result is crazy, difficult to read tests. It may be helpful to set up the starter kettle or learn to match something you are unsure of. Otherwise, stay away from it.

Performing an action

Your users do more than just open the app. They tap and interact with the items on the screen. When they do an action, they expect the right to happen and you should test to make sure it always does!

In this app, if you select one of the buttons without entering a total, the result is empty. Add a test that when you click the 👍 button ( Okay ), the tip result is empty:

  @Test
funny when OkayButtonIsPressedAndAmountIsEmptyTipIsEmpty () {
ActivityScenario.launch (MainActivity :: class.java)

// 1
onView (withId (R.id.buttonOkay))
.Please (click ())

// 2
onView (allOf (withId (R.id.textTip), withText (""))))
.Check (matches (isDisplayed ()))
}

There are two new things, here:

  1. After matching the button with the ID you learned with the other views, call .perform (click ()) on it. You can combine matches with .perform () to make a variety of actions in a view.
  2. There is an extra layer of nesting in this match. You can tell Espresso that it must match both conditions on the display using allOf () .

    Use the package org.hamcrest.Matchers.allOf when prompted to import allOf () . This says that you want the display with ID textTip and with an empty string like the text. If all of these conditions are not met by a display on the screen, the test will fail.

Again, run your tests and see that they are passing by!

 Four Espresso Tests Passed Tests

Typing Text

Another action you will most likely often perform is writing in some text. Add a test for when entering a quantity, then press the 👍 button ( Okay ), the display shows the correct tip.

  @ Test
funny when OkayButtonIsPressedAndAmountIsFilledTipIsSet () {)
ActivityScenario.launch (MainActivity :: class.java)

// 1
onView (withId (R.id.inputAmount))
.Please (typeText ("11"))

onView (withId (R.id.buttonOkay))
.Please (click ())

// 2
onView (withId (R.id.textTip))
.check (matches (withText ("1.98")))
}

Most of this is similar to other tests. Here's what's new:

  1. Declaration to enter "11" in the entrance. You use a match that you have learned and then call .perform (typeText ("11")) to enter the text in the field.
  2. You verify that the display with ID textTip has the correct text using withText () instead of combining allOf () and isDisplayed () . This is an alternative way to perform this check.

Run it and add it to your collection with green tests!

 Five Espresso Tests Passing Tests

Writing Individual Responsibility Test

Each of your tests should only test one thing . You want individual responsibility tests, so when something goes wrong, you have a clear indication of why. This is why you do not test for the presence of the entry in the same test you fill in content.

To continue to have one responsibility for each test, write another who checks the tip value when you have the round up to the nearest dollar switch turned on:

  @Test
funny when OkayButtonIsPressedAndRoundSwitchIsSelectedAmountIsCorrect () {
ActivityScenario.launch (MainActivity :: class.java)

onView (withId (R.id.witchRound))
.Please (click ())
onView (withId (R.id.inputAmount))
.Please (typeText ("11"))
onView (withId (R.id.buttonOkay))
.Please (click ())

onView (withId (R.id.textTip))
.check (matches (withText ("2.00")))
}

This is almost exactly the same as the previous test, except for adding the sentence to click on the switch to turn it on and confirm another amount.

As always, they run the tests again. :]

 Six Espresso tests pass tests

Printer Robots

As the last two tests show, test writing may be repetitive. You can extract much of this duplication to be reused. One great way to do this is to use Screen Robots .

Screen Robots extract some of these tasks into helper functions. This makes testing more expressive, readable and easier to update if something in the user interface changes. For example, if an ID changes, instead of updating it in a bunch of separate tests, you can update it in one robot.

You can think of a robot as an intermediary between your display and a test: It serves the same purpose as a presenter in MVP architectural pattern. The vision itself knows nothing about the test and the test knows nothing about the implementation of the display, it only knows what actions it needs to perform on a view.

Using robots, you can easily distinguish the concerns that benefit you from changing the robot only if the display changes.

 Robot Pattern in MVP Architecture

Start by creating a class extending ScreenRobot . This can be an internal class to your test added to the end of your file outside the test or in a nearby file. You can make this decision based on whether you want to use the robot elsewhere.

When this robot is only used in this test, this project adds it as an inner class to MainActivityTest :

  class CalculatorScreenRobot: ScreenRobot  () {

}

ScreenRobot that this class inherits is another file already defined for you in the app. Take a look at ScreenRobot.kt if you are curious. It has some useful methods to use as enterTextIntoView () clickOkOnView () and checkViewHasText () .

Then write some robots! Start with an easy to confirm tip amount. Add this to CalculatorScreenRobot :

  Fun VerifyTipIsCorrect (tip: String): CalculatorScreenRobot {
return checkViewHasText (R.id.textTip, tip)
}

The interface of a robot returns a robot so that you can keep contiguous actions and statements together. Here, just use one of the helpers to make sure that a view has some specific text and return the ScreenRobot result, this . If you look at the method, you see a check similar to the one you replace with it.

To take advantage of this chain, add an action to enter a check amount and click the button. Add this CalculatorScreenRobot :

  funny inputCheckAmountAndSelectOkayButton (input: String):
CalculatorScreenRobot {
return enterTextIntoView (R.id.inputAmount, input)
.clickOkOnView (R.id.buttonOkay)
}

Here you associate the help functions to enter text and click the button.

Using the Screen Robots

Now that you've written them, you can replace some of your tests with robots! Replace the body to when the OkayButtonIsPressedAndAmountIsFilledTipIsSet () with this:

  ActivityScenario.launch (MainActivity :: class.java)

withRobot (CalculatorScreenRobot :: class.java)
.inputCheckAmountAndSelectOkayButton ("11")
.verifyTipIsCorrect ("1.98")

You start by using CalculatorScreenRobot using with Robot () . Then you can link your actions and statements together. See how much more declaring this is! Reading and understanding what's happening is so much easier.

If you run the tests, the result must be the same.

 Six Espresso tests pass tests

You can use these robots in another location. Replace the body to when OkayButtonIsPressedAndRoundSwitchIsSelectedAmountIsCorrect () with the following:

  ActivityScenario.launch (MainActivity :: class.java)

withRobot (CalculatorScreenRobot :: class.java)
.clickOkOnView (R.id.switchRound)
.inputCheckAmountAndSelectOkayButton ("11")
.verifyTipIsCorrect ("2.00")

Here you have added .clickOkOnView () from the base class to the chain to turn on the switch. Everything else is the same.

 Six Espresso tests pass tests

Can you begin to see the possibilities of these robots? You can make your robots as simple as clicking on a single button or just as complicated as filling out a complicated form. Use them for what makes the most sense in your app to make things reusable and readable.

Where to go from here?

Wow! You learned so much in this tutorial. Not only did you learn how to write Espresso tests, but also how to use Screen Robots to make them shorter and easier to read. You can download the final result using the Download materials button at the top or bottom of this tutorial.

Itching to practice this more and try some of the other robot options? As a challenge, you can complete testing this screen. Here are some ideas on what to test next:

  • The rest of the views are displayed at the launch.
  • Results of each of the three buttons: Tips Total and Percentage show when:
    • The input is empty.
    • The input is filled and the rounding off.
    • The entrance is filled and the rounding is on.

Sure, you can extract most of this and move it to Unit Tests, but what do you practice? You can find a solution to the challenge using the Download Materials button at the top or bottom of the screen.

Play around with test robots to see if they work well for you. It takes time and practice to develop the intuition to know which robots will be most valuable and how to write long-lasting, sustainable tests.

You can continue to learn in these places too:

We hope you found this useful! If you have comments or questions, please join us in the forum below.


Source link