Back to Resources

Blog

Posted August 27, 2013

Guest Post: Automated iOS Acceptance Testing with Appium, Cucumber-JVM, Jenkins, and Sauce Labs Part 3

quote

For all you folks following along at home, we've been posting a series of guest posts written by Unmesh Gundecha, testing guru and author of Selenium Testing Tools Cookbook. Here we have the last post in his series, which takes the mobile tests he's discussed running on a local environment and running them on Sauce with Appium. Many thanks to Unmesh for this awesome and thorough series. And let us know what other mobile testing topics you'd like to read about. Read on for the final part! _________________________________

Running on Sauce Labs

So far we executed features on a local environment. Now this is just one feature, there could be 100s of such and you might want to run these features frequently. Setting up dedicated machine may not be always possible and involves costs. Sauce labs, the company behind Appium, provides you an ability to run Appium tests in a virtual environment without needing you to setup everything from scratch. This also saves you costs for setting up the infrastructure on your own. But at times you may also want to run these on a local environment, how do we support both running in local environment and sauce? Let’s use Tags and Hook feature of Cucumber. We already have a setup method which connects to a local Appium sever using the RemoteWebDriver. Let’s add a tag to this method: @Before("local") public void setUpLocal() throws Throwable { ... } And add another setup method setUpiOS() and add “ios-sauce” tag to it:

@Before("@ios-sauce") public void setUpiOS() throws Throwable { DesiredCapabilities capabilities = new DesiredCapabilities(); capabilities.setCapability(CapabilityType.VERSION, "6.1"); capabilities.setCapability(CapabilityType.PLATFORM, "Mac"); capabilities.setCapability("app", "sauce-storage:my_ios_app.zip"); capabilities.setCapability("device", "iPhone Simulator"); String sauceUserName = System.getenv("SAUCE_USER_NAME"); String sauceAccessKey = System.getenv("SAUCE_ACCESS_KEY"); //Create an instance of RemoteWebDriver and connect to the Appium server. //Appium will launch the BmiCalc App in iPhone Simulator using the configurations specified in Desired Capabilities driver = new RemoteWebDriver(new URL(MessageFormat.format("http://{0}: {1}@ondemand.saucelabs.com:80/wd/hub", sauceUserName, sauceAccessKey)), capabilities); }

This allows selectively run features on desired environment. For example if you wish to run scenario on Sauce Labs, then you need to specify the “ios-sauce” tag on the scenario definition in feature file @ios-sauce Scenario Outline: Calculate Body Mass Index … This will run the feature on Sauce Labs environment. If you specify “local” then it will run the feature on local Appium setup. Here is the complete code example:

package bmicalculator.test; import java.net.URL; import java.text.MessageFormat; import cucumber.annotation.*; import cucumber.annotation.en.*; import static org.junit.Assert.assertEquals; import org.openqa.selenium.remote.CapabilityType; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.remote.RemoteWebDriver; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.By; public class Bmi_Calculator_Step_Defs { private WebDriver driver; @Before("@local") public void setUpLocal() throws Throwable { //Setup for running Appium test in local environment DesiredCapabilities capabilities = new DesiredCapabilities(); capabilities.setCapability(CapabilityType.BROWSER_NAME, "iOS"); capabilities.setCapability(CapabilityType.VERSION, "6.1"); capabilities.setCapability(CapabilityType.PLATFORM, "Mac"); capabilities.setCapability("app", "/Users/upgundecha/Desktop/AppExamples/BmiCalculator/build/Release-iphonesimulator/BmiCalculator.app"); //Create an instance of RemoteWebDriver and connect to the Appium server. //Appium will launch the BmiCalc App in iPhone Simulator using the configurations specified in Desired Capabilities driver = new RemoteWebDriver(new URL("http://0.0.0.0:4723/wd/hub"), capabilities); } @Before("@ios-sauce") public void setUpiOS() throws Throwable { DesiredCapabilities capabilities = new DesiredCapabilities(); capabilities.setCapability(CapabilityType.VERSION, "6.1"); capabilities.setCapability(CapabilityType.PLATFORM, "Mac"); capabilities.setCapability("app", "sauce-storage:my_ios_app.zip"); capabilities.setCapability("device", "iPhone Simulator"); String sauceUserName = System.getenv("SAUCE_USER_NAME"); String sauceAccessKey = System.getenv("SAUCE_ACCESS_KEY"); //Create an instance of RemoteWebDriver and connect to the Appium server. //Appium will launch the BmiCalc App in iPhone Simulator using the configurations specified in Desired Capabilities driver = new RemoteWebDriver(new URL(MessageFormat.format("http://{0}:{1}@ondemand.saucelabs.com:80/wd/hub", sauceUserName, sauceAccessKey)), capabilities); } @Given("^I enter \"([^\"]*)\" as height$") public void I_enter_as_height(String height) throws Throwable { WebElement heightTextField = driver.findElement(By.name("Height")); heightTextField.sendKeys(height); } @Then("^I enter \"([^\"]*)\" as weight$") public void I_enter_as_weight(String weight) throws Throwable { WebElement weightTextField = driver.findElement(By.name("Weight")); weightTextField.sendKeys(weight); } @Then("^I press the Calculate button$") public void I_press_the_Calculate_button() throws Throwable { WebElement calculateButton = driver.findElement(By.name("Calculate")); calculateButton.click(); } @Then("^I should see \"([^\"]*)\" as bmi and \"([^\"]*)\" as category$") public void I_should_see_as_bmi_and_Normal_as_category(String bmi, String category) throws Throwable { WebElement bmilabel = driver.findElement(By.name("bmi")); WebElement bmiCategorylabel = driver.findElement(By.name("category")); //Check the calculated Bmi and Category displayed assertEquals(bmi,bmilabel.getText()); assertEquals(category,bmiCategorylabel.getText()); @After public void tearDown() { driver.quit(); } }

The complete source code for the sample App and test is available at https://github.com/upgundecha/BmiCalculator

Using Continuous Integration

Continuous Integration (CI) is becoming a widely accepted practice in agile projects for early feedback. Each integration is verified by an automated build to detect errors as quickly as possible. CI also gives great visibility to all stakeholders about the overall health of the project and its progress. Jenkins is one of the popular CI tool used by the teams. You can setup the build and test jobs on Jenkins for this project.

Building the App with Jenkins

For building the App with Jenkins, create a new Build a free-style software project Job. The sample App source is hosted on GitHub. Configure the Git repository and point it to the GitHub repo as show in below screen shot Next, configure the build trigger, so every time a change is submitted to Git, this job will be trigger a new build of the App. Once the App is built it will be uploaded to the Sauce Labs temporary storage area so the test job can run acceptance tests on the build.

Running Acceptance tests with Jenkins

For running acceptance test after a successful build, create a new Build a maven2/3 project job in Jenkins with following parameters In the Build Trigger section configure Build after other project are built and specify name of the earlier job. This will automatically run acceptance test (i.e. current job) when the App build is successful Cucumber provides a report plugin for Jenkins which provides a nicely formatted interactive web reports as shown in below screenshot:

Summary

We can write acceptance tests for native mobile Apps with Cucumber, Selenium WebDriver API and Appium. These can be run on local or Sauce Labs environment. We can also get benefits of whole team communication and early feedback by applying these methods in mobile application development.

Published:
Aug 27, 2013
Share this post
Copy Share Link
© 2023 Sauce Labs Inc., all rights reserved. SAUCE and SAUCE LABS are registered trademarks owned by Sauce Labs Inc. in the United States, EU, and may be registered in other jurisdictions.