March 02, 2017

Why Appium is the better option for us


For our monthly “crazy programming Friday”, we decided to try out Appium and maybe get a new testing framework for our end-to-end tests on iOS and Android, which would replace the current system. The system in place is Calabash, which is written in Ruby and, on top of that, feature files in Gherkin and Cucumber. Calabash has the nice ability to be written for both iOS and Android in the same language, so this was something we needed for our new tool as well. Luckily, Appium provides exactly this.


Appium – What is it?

Appium is a testing framework that uses the Selenium WebDriver protocol and has some additional features to make it feasible with native, hybrid, and mobile web apps. The language you write your tests in is completely up to you –that’s why it was an interesting tool to test out, because Calabash, which we have been using until now, restricts the developer to Ruby. Ruby is not hard to learn, but if most developers are more familiar with Java, it can be a barrier to overcome. Appium enables developers to write end-to-end tests for mobile applications in Java. Further information can be found on the Appium homepage.

Set-up and First Try

Appium’s developers provide a Github repository, so trying out Appium is not a problem. It provides you with some tests and a basic set-up where you can configure which app you want to launch in the simulator, different options for timeouts, and how to create a local Appium service. After we tried their tutorial, we wanted to get our own iOS application up and running; this was a little bit tricky, because we use XCode 8 and iOS 10, which caused some problems with the current version of Appium. In our case, we had to use Appium version 1.6.3, which was not fully stable at the time. One other problem was that the server wouldn’t start when we launched the tests, due to the default IP address that is used.

As previously mentioned, we were using Gherkin feature files, and we wanted to reuse them in the new test cases as well. This is no problem with Appium, as you can just use an annotation that specifies the storage location of the feature files. It is also possible to start only one feature, should this be necessary.
 @RunWith(Cucumber.class)  
 @CucumberOptions(  
     features = {"classpath:features/aza.feature"},  
     glue = {"classpath:at.willhaben.stepdefinitions"},  
     strict = true,  
     plugin = {"junit:reports/ios_results.junit.xml"},  
     tags = {"@ios_phone,@ios_tablet"}  
 )  
For testing only a single test that has failed before, or if you are working on one particular test, this can be helpful.
Again, the tests can be written in nearly every main language used for automated tests. With this in mind, we switched to Java, and the framework uses most of the commands that are also used in Selenium. You have to set up a driver that is connected to the application and gives you all the information about the elements that are accessible. This is similar to the set up for a Selenium driver.
For our tests, we used the page object pattern, which provides a clean separation between the different pages in the application and helps reading the code.

Here are some code samples of a test we already have in use:
The first is the feature file that represents the test in an abstract form.
 Feature: AZA  
 @android_phone @ios_phone @ios_test @nexus5  
 Scenario: BAP AZA WITH PAYMENT  
      Given the App has started and I am on the Main Screen  
      When I click on login  
      Then I log in with valid credentials  
      And I start Aza from Main Screen  
      And I select Bap Free Aza  
      #And I take a Picture  
      And I fill out the AZA form with:  
       | Title     | not the Default-Title    |  
       | Price     | 13.17            |  
       | Category1       | Kameras / TV / Multimedia      |  
       | Category2       | Kameras / Camcorder           |  
       | Category3       | Camcorder / Actionkameras      |  
       | Description  | not the default description |  
       | Address    | Fakestreet 123       |  
       | PLZ      | 1180            |  
This is the step definition file where you specify the steps to be taken and initialize the page objects.
 @Then("^I fill out the AZA form with:$")  
   public void i_fill_out_the_AZA_form_with(DataTable arg1) throws Throwable {  
     Map<String,String> map = arg1.asMap(String.class, String.class);  
     BapAzaFirstPage bapAzaFirstPage = pageObjectFactory.createBapAzaFirstPage();  
     String title = map.get("Title");  
     List<String> categories = map.entrySet()  
         .stream()  
         .filter(entry -> entry.getKey().startsWith("Category"))  
         .sorted((e1, e2) -> e1.getKey().compareTo(e2.getKey()))  
         .map(Map.Entry::getValue)  
         .collect(Collectors.toList());  
     Map<String,String> keys = map.entrySet()  
         .stream()  
         .map(Map.Entry::getKey)  
         .collect(Collectors.toMap(  
             s -> s,  
             s -> s  
         ));  
     bapAzaFirstPage.enterPrice("22,70");  
     bapAzaFirstPage.enterTitle(title);  
     bapAzaFirstPage.enterDescription("eine schöne Beschreibung");  
     CategoryPickerPage categoryPickerPage = bapAzaFirstPage.clickChooseCategory();  
     categoryPickerPage = pageObjectFactory.createCategoryPickerPage(categoryPickerPage);  
     categoryPickerPage.clickChooseCategoryManually(categories);  
     String make = map.get("Marke");  
     String type = map.get("Kameratyp");  
     String condition = map.get("Zustand");  
     String handover = map.get("Übergabe");  
     bapAzaFirstPage.chooseSingleSelect(keys.get("Marke"), make);  
     bapAzaFirstPage.chooseSingleSelect(keys.get("Kameratyp"),type);  
     bapAzaFirstPage.chooseSingleSelect(keys.get("Zustand"),condition);  
     bapAzaFirstPage.chooseMultiSelect(keys.get("\u00DCbergabe"),handover);  
Here is an example of how to find a textfield and then access it afterwards.
 @iOSFindBy(accessibility = "Aza_Field_Price")  
   WebElement priceTF;  
   
   @iOSFindBy(accessibility = "Aza_Field_Bap_Title")  
   WebElement titleTF;  
   
 public void enterTitle(String title){  
     elementsPresentWithException(titleTF);  
     titleTF.sendKeys(title);  
     getDriver().hideKeyboard();  
   }  
   
   public void enterPrice(String price){  
     elementsPresentWithException(priceTF);  
     priceTF.sendKeys(price);  
   }  

Appium Inspector

The Appium Inspector is an additional provided tool. It is used for getting the attributes of all items in the app. Think of it like the Accessibility Inspector from XCode, but this provides a better GUI and more information about buttons, textfields, etc., as you can see here.



















Every element is described and is ordered by the layer where it is found, and the current simulator screen can be refreshed if you want to check the next page. Another option is to record the steps you take on the simulator. This is possible with iOS and Android, and it is even possible to use a real device, if it is connected and found by Appium.

We found it a bit tricky to start the Appium Inspector with iOS 10, because the highest platform version that is currently selectable is 9.3.

If you want to use the Inspector, you have to start the Appium server over the console. The following command starts the server with the option of a full reset. We did this because we wanted to have a clean simulator to work with.
appium --default-capabilities '{"fullReset":true}' 

After the server is running, start the Appium program and open the settings for iOS. There, you won’t need to select a platform version from the dropdown menu, just type the wanted version into the text field. After that, you are good to go with the Appium Inspector.

One thing that has to be noted is that Appium does not support the GUI Inspector, and this will create some issues with the development of the tests. For now, we will use it to get the elements, but not for any recordings or other similar things. If you need more information on the Appium Inspector and some help with common topics, you can find it in the discussion forum or the Appium Github.

Summary

Appium provides a lot of functionality for developing automated end-to-end tests for iOS and Android applications, and is helpful if you want to stick with your main programming language, the one your developers are most comfortable with. The Inspector is nice to have, but you can use the pageSource method or the standard inspector from iOS as well. We will use it for the automation of our applications, and we think it is a good choice if you already use Selenium in your core projects.

1 comment:

  1. Massive post. Really good-looking blog. A lot of blogs, I observe these days don't really present anything that I'm interested in custom essay writing service .but I'm most definitely interest in this one. I am in reality happy with article quality and direction. This post is mark on in helpful how some thought apply to any script point. Thanks a lot for protection enormous things. I am enormously a good deal thankful used designed for this place.

    ReplyDelete