Jump to Section

    Chapter-16: End-to-End testing.

    We’ve covered a lot up until this point. If you’ve stuck with us, you should hopefully feel far more knowledgeable about Appium. Don’t worry if you feel it hasn’t all quite “come together” yet. Start small and write some simple test cases. You don’t need to use the advanced concepts like our design patterns until you become more comfortable with the basics of Appium.

    This chapter aims to help you bring in all the moving pieces and combines everything you’ve learned up to now by showing you how to apply all your knowledge in an “end-to-end” test. At times we’ll reference previous sections, and we’ll also rehash some information we’ve previously covered. Seeing coverage from another angle will help solidify your knowledge.

    This chapter is divided into 4 sections:

      • 1) Setting up Appium.
      • 2) Test Planning.
      • 3) Test Setup.
      • 4)Test Case Writing and Execution.
        • 1) Setting up Appium:

          • This is a section we won’t repeat here as it was covered extensively in the first chapter. Setting up environments isn’t ever any fun but once it’s setup you’re good to go. We’re going to assume you have everything setup - and refer to the first chapter if you need some help.

        • 2) Test Planning:

          • As the expression goes - “Measure twice, cut once”. Some planning up-front is going to save you a lot of headache later on. And good test planning means a little experimentation with manual testing before starting automation. Specifically:

              1. The first thing is you need to check application compatibility or suitability for automation testing. You can check that by verifying the values of selectors using the locator inspection tool (Appium accessibility inspector or UiAutomator). You can quickly assess the locators of basic UI elements such as username field, password field, login button etc. and if you don’t find unique locators for them you’re going to need to use Xpath which is less than ideal. If at all possible, work with the development team to see if they can assign unique locators to UI elements.
              2. After verifying the availability of unique locators, you need to explore the whole application thoroughly, you need to understand each and every feature of the app and need to prepare the list of the most important ones. After preparing the list you can prepare manual test cases. With automation and parallel execution, keep in mind that your test could be executed in a random order at any point of time so it should be very granular, and it is important that the test cases you design are modular and independent.
        • 3) Test Environment Setup:

          In order to perform automation using Appium you need to:

            1. Write the code which will find the UI element on the screen.
            2. After getting the element, write the code which will perform an action upon it.
          • This is all done within your test code - the Appium server will interact with the application artifacts(.ipa or .apk) and your test code:

            Figure-1: Appium Process.

            So you can create a native mobile application on XCode(for iOS) and Android Studio(for Android) OR you can also use the build (.ipa/.apk) directly, write the UI test cases in your preferred programming language and executes them manually from the IntelliJ IDEA, Eclipse IDE, Visual Studio or IntelliJ PHPStorm.

            Moreover, if you want to achieve end-to-end automation and want UI test cases as the part of your CI/CD process then you can also integrate them with tools such as Jenkins and BitBucket.

            So first thing first is you need to get the build(.ipa/.apk), choose the programming language for your automation code and get the physical device/Simulator/Emulator for testing.

        • 4) Test Case Writing:

          • After designing the test cases and setting up the test environment you can start writing the test cases. For illustrative purposes, we will be automating the Android messaging app from Google. To reemphasize best practices, we will utilize the page object model to create a cleaner and more modular solution. Because we already discussed the page object model framework in detail previously, we can save time by cloning the automation framework project we used previously which you can find on github here.

            Now let’s discuss the scenario which we want to automate. We have taken Google message application(v 3.9.039) for the automation.

            But before starting the automation we will need to plan our test. So as per our above discussion, we need to take care of 2 things.

              1. We need to quickly check the app feasibility for automation and to do so we need to verify that the locators of the app are unique. Here we will use uiautomatorviewer to find the unique locators of UI elements as it is quick on Android compared to the Appium inspection tool.

                Figure-2: Quick check of locators on messaging app.

                As you can see above, the button has a unique resource-id - The Google developers have assigned unique ids to all UI elements, so the first step is clear.

              2. The Google message app is straightforward - you can explore the whole application and can get an idea of each feature. As the application is mainly designed to send an SMS to contacts we will need to automate the most important scenario which is sending the SMS to a particular contact.

                Here are the manual steps we will perform and then use this to create the automation:

                No. Test Steps Expected Output
                1 Open the google message application. An app should open.
                2 Tap on ‘Start chat’ OR ’+’ button. New conversion screen should appear.
                3 Type the contact no. in ‘To’ textfield. ‘Send to contact no.’ row should be visible.
                4 Tap on the suggested contact below search box.(like ‘Send to 111-1111’) Conversation screen should appear.
                5 Type into the message textfield. A message should be typed correctly.
                6 Tap on ‘SMS’ button Message should be sent to the recipient.

                Now, both the conditions are satisfied so we can move forward and start writing the automation test case.

                We will use the page object model framework for writing the automation test case and using it involves just a few steps - it may seem like overkill for this test case but we’re putting in a good baseline for a larger more sophisticated automation project:

                  • 1) You can get the POM-based automation framework from our GitHub page.

                  • 2) Import as gradle project in IntelliJ IDEA/Eclipse IDE.

                  • 3) Run the build.gradle file in order to download all dependencies.

                  • 4) Move to the configuration.properties file and change these properties as per the connected Android device. android.platform.version=android.device.name=

                  • 5) Set the proper desired capabilities.

                  • 6) Get the unique locators for UI elements on the app.

                  • 7) Create the page objects of different screens.

                  • 8) Write the automation test case using the created page object’s methods.

                The First 4 steps are straight forward - now we get to the desired capabilities part!

        • Set desired capabilities

        • Because the app we have chosen comes pre-installed on Android devices, we can skip the installation and go straight to opening the app.

          					DesiredCapabilities desiredCapabilities = new DesiredCapabilities();
          					desiredCapabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, "uiautomator2");
          					desiredCapabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "c4e3f3cd");
          					desiredCapabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
          					desiredCapabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "8.0");
          					desiredCapabilities.setCapability(AndroidMobileCapabilityType.APP_PACKAGE, "com.google.android.apps.messaging");
          					desiredCapabilities.setCapability(AndroidMobileCapabilityType.APP_ACTIVITY, "com.google.android.apps.messaging.ui.ConversationListActivity");
          					desiredCapabilities.setCapability(MobileCapabilityType.FULL_RESET, false);
          					desiredCapabilities.setCapability(MobileCapabilityType.NO_RESET, true);
          					desiredCapabilities.setCapability(AndroidMobileCapabilityType.AUTO_GRANT_PERMISSIONS, true);

          Here, we don’t use the desiredCapabilities.setCapability(MobileCapabilityType.APP, ); capability because we are not installing the application.

        • Getting the unique locators

          • After setting the desired capabilities you need to extract the selectors using uiautomatorviewer(or Appium inspector) for all the UI elements we need to control.

            NOTE: The Google message application will change periodically so there are chances that the element IDs may change over time, so please modify the automation script accordingly.

            There are typically 4 screens we need to take care of for automating our scenario:

              1. Messages (Dashboard) screen.
              2. New conversation screen.
              3. New conversation screen for a new contact.
              4. Conversation screen.

            Figure-3.1: Google message app Message_New conversation screens1.

            Figure-3.1: Google message app Message_New conversation screens2.

            Figure-3.1: Figure3-2-Google message app New conversation_Conversation screens1.

            Figure-3.2: Google message app New conversation_Conversation screens2.

            After identifying the screens we need to get the selectors of each element from all screens which will be needed while automating our test case.

            So let’s make a list:

            Screen Name Element Locator
            Messages ‘Start chat’ button ID: start_new_conversation_button Or ID: com.google.android.apps.messaging:id/start_new_conversation_button
            New conversation ‘To’ textfield ID: recipient_text_view
            New conversation ‘Send to 432-5235’ textview Not present on DOM, but we can skip this by tapping on ENTER from keyboard.
            Conversation SMS Message textfield ID: compose_message_text
            Conversation ‘SMS’ button ID: send_message_button_container
            Conversation Sent Message layout XPath: //android.support.v7.widget.RecyclerView/android.widget.FrameLayou

            NOTE: You can use the ID selector in these formats:

              1. start_new_conversation_button
              2. com.google.android.apps.messaging:id/start_new_conversation_button

            If you look at the above table closely you can notice that most of elements have unique Ids, however a few elements have some issues with their id:

              1. ‘Send to 432-5235’ textview is not present in DOM at all so we can’t locate that element.

                Figure-4: Selector of Send to 4325235 textview is not present in DOM.

            So, we need to look for a workaround. If you look closely at this screen than you might figure out that you just have to press the ‘correct’ (green check mark) icon on the keyboard and you don't need to press the ‘Send to 432-5235’ textview.

            Figure-5: Use Right Icon instead of ‘Send to 4325235’ textview.

            We can click on the icon from the soft keyboard:

            driver.pressKey(new KeyEvent().withKey(AndroidKey.ENTER));
              1. The 2nd issue is there is no unique id assigned to the sent message textview. So we need to look at another locator strategy. What about using the accessibility id locator strategy? Unfortunately that would only work if the id is static and here it keeps changing, so that strategy won’t work either.So the XPath locator strategy remains. It’s actually good practice to use the text attribute in XPath but if you see the below screenshot you can find that there is no text assigned to the sent message textview. So we will need to use XPath as follows:
            @AndroidFindBy(xpath = "//android.support.v7.widget.RecyclerView/android.widget.FrameLayout")
            List sentMessageLayout;

            This game of finding the right locator strategy to use is very common in test automation. You’ll explore the elements and then go through a process of trying to find what the best locator strategy is in order to reach those elements.

            You may be wondering why we have taken the List of AndroidElement ? This is because the problem with the single AndroidElement is if you have multiple messages sent to the same mobile number it will always take the first element but we need the last element of the sent message. Please see Figure-7: FrameLayout presents for each sent message.

            Figure-6: Id is not assigned to sent message textview.

            Figure-7: FrameLayout presents for each sent message.

            Now that we have all the unique locators which we wanted, we can start creating our actions in the PO classes.

        • Create action methods in PO classes

        • We need to create action methods on Page Object classes which will tap on buttons, fill the text fields and assert text values on the app screen.

          For example, on the Message(Dashboard) screen we need a method which will tap on the ‘Start chat’ button. We already have the selector of the ‘Start button’ so we can create our method:

          					public class MessagesPO extends BasePO {
          				    public MessagesPO(AppiumDriver driver) {
          				    @AndroidFindBy(id = "com.google.android.apps.messaging:id/start_new_conversation_button")
          				    AndroidElement startChatButton;
          				    public NewConversationPO tapOnStartChatButton() {
          				        return new NewConversationPO(driver);

          Why does our tapOnStartChatButton() method return a new object of NewConversationPO? The answer is that whenever any method is responsible to change the screen we can return the object of the subsequent screen’s PO class so that we don’t need to create the object of that PO class separately while writing test case.

          Here, the method tapOnStartChatButton() will tap on ‘Start chat’ button which will navigate to the New Conversation screen so we are returning the object of NewConversationPO class.

          This practice is not mandatory but it is good to have.

          NOTE: All PO class should extend the BasePO class as it contains the logic which initializes the page factory and other utility classes. You can look into the chapter titled: “Developing Test Automation Framework for Appium using Page Object Modeling(POM)“ for more details.

          We have created the below table which gives the mapping between screen names and corresponding method names.

          Screen Name Method Name
          Messages tapOnStartChatButton(): It will tap on Start chat button.
          New conversation typeAndSubmitContactNumber(String contactNo): It will type the contact no. and submit it for conversation.
          Conversation typeInSMSTextField(String text): This method will type into message textfield.
          tapOnSMSButton(): This method will tap on the SMS button.
          isConversationScreenDisplayed(): This method is used to verification purpose, it will return true if conversation screen appears.
          getLastSentMessage(): It will return the AndroidElement for last sent message.
          getLastSentMessageText(): This method is used to get the last sent message text.
          isMessageSent(): It will verify that message is sent or not.
          isLastSentMessageContains(String subString): This method will check whether last sent message contains the passed subString or not
        • Create the test case and use action methods from PO classes.

        • This is the final and easiest, yet most powerful, step of automation test case writing. Here you have to organize all the methods from your PO classes in order to make the complete automation test case and validate the result using assertions.
        • Assertions are fundamental in test case writing - without them you’re just doing automation, and not automated testing. Ideally, you would put as many assertions as you can. Assertions can be thought of as checkpoints. At the end of any action method you will have some expected results, and to measure those expected results you have to put assertion statements in the code.
        • In our example we are using the TestNG assertions.
        • Assertions simply compares the value of expected and actual values. If the expected and actual values are equal then the assertion ‘passes’ and we continue with code execution. If it fails (the actual result does not match the expected result) the user defined message is thrown.

    In our example we have 2 assertions:

          • 1) Verify that the message has been sent to the user:
              • Here we want to check that the application has sent the message and is being displayed on the conversation screen.

                								Assert.assertTrue(conversationPO.isMessageSent(), "Message:'" + messageText + "' is not being sent!");

                The 2nd parameter is the error message we want to throw in case of failure of the assertion. A good error message should give sufficient information about what it is checking, so that your diagnostics becomes easier.

          • 2) Verify that sent message is as per expectations:
              • Checking that the message is sent is one thing … but was the right message sent? As discussed earlier there is no unique id assigned to the sent message text view, so we can not get the text of the last message. We can however get the whole FrameLayout text.

                So logically we can have an assertion which will check that the expected text is present on the last sent message or not. In our example, we have put the timestamp in milliseconds in a text message and we will verify that given timestamp text value is present on last sent message or not.

                								Assert.assertTrue(conversationPO.isLastSentMessageContains(timestamp), "Last sent message is different than expected!, Original message is: '" + conversationPO.getLastSentMessageText() + "', while the expected substring is: " + timestamp + "'");

                After organizing the action methods from the PO and adding our assertions we have our complete test case which will send the message to a particular contact number.

                								public class TestCases extends BaseTest {
                							    public void verifyUserCanSendMessage() {
                							        final String phoneNo = "00011122233";
                							        final String timestamp = System.currentTimeMillis() + "";
                							        final String messageText = "Hello, there. Current time is: " + timestamp;
                							        MessagesPO messagesPO = new MessagesPO(androidDriver);
                							        NewConversationPO newConversationPO = messagesPO.tapOnStartChatButton();
                							        ConversationPO conversationPO = newConversationPO.typeAndSubmitContactNumber(phoneNo);
                							isConversationScreenDisplayed(), "Conversation screen didn't appear!");
                							        Assert.assertTrue(conversationPO.isMessageSent(), "Message:'" + messageText + "' is not being sent!");
                							(timestamp), "Last sent message is different than expected!, Original message is: '" + conversationPO.getLastSentMessageText() + "', while the expected substring is: " + timestamp + "'");
                							    public void setUpPage() throws MalformedURLException {
                							        androidDriver = new AndroidDriver(new URL(APPIUM_SERVER_URL), getDesiredCapabilitiesForAndroid());

                The full code is available on github here.

                As we said at the outset, this app may have changed by the time this guide was published. A new UI could render some of our test cases invalid. We have however tried to lay out a methodical and disciplined approach to tackling any test automation project. You should be to apply this approach for any mobile application.