iOS and Android apps automation

Embed Size (px)

Text of iOS and Android apps automation

Apps Test Automation

iOS and Android Apps automation By, Sridhar RamakrishnanLife long travel geek @ Hotwire Inc.

AgendaHow is Native app testing is different from Web testingKind of Native app bugsTest automationDifferent framework for native apps automationWhat is appium & how it worksAndroid & iOS frameworks Espresso & Xcode UI testingSample test codeDemoCode CoverageOur CI processScreenshot testing Image comparison testsTrackingSo why we are doing all this??

How is Native app testing is different from Web testing

Usability & interactionFaster & more reactiveInvolves GesturesNo unnecessary content

Data Entry Keyboard TypesNumeric vs. Alphanumeric

Phone SettingsChanging RegionsChanging Location ServicesChanging Notifications

Devices vs. Simulators

Multiple Devices and Operating Systems

Bugs TypesCrashesMissing data from the APIMissing data in the appWrong keyboard displayedRendering differences across devicesViews overlaying one anotherViews are getting locked upGesture related swipe, double tap

More Bugs ?Limited manual regression testing = Spot check ; less boringMore manual exploratory testing = More bugs;Simultaneously learning about the system while designing and executing tests, using feedback from the last test to inform the next. - Elisabeth Hendrickson

Test Automation

Frameworks comparison

Frameworks for comparisonTest the actual appMany languageStandard API ( Webdriver)Open source & active BDDiOSAndroidHybridFirefox OSAppiumXcode UI Automationcalabash-iOSFrankios-driverKIFRobotiumEspressoselendroid

Test Automation @ HotwireTest Framework = Hotwire BDDTools =

Xcode UI testing

API = Spoofer (mock) vs API calls

Appium Multi OS Support

And More

Appium ArchitectureTest Script ( Java )Webdriver (Seleium Java)Apple Instruments (Instruments.js)iPhone / iPad[Simulator / Device]APPAndroid[Simulator / Device]APPAndroid (adb, UIAutomator (AppiumBootstrap.jar )

FireFox OS / Hybrid AppsFirefox OS / Web browserBDD (Cucumber, Webdriver, Spring, maven)

CI Jenkins (Build xcode, start Appium server, mvn install

Appium server (Node.js)JS

JSON

BDD Cucumber & GherkinFeature: Hotel Search and Book

Scenario: Search and book hotel as Sign In user Given I'm searching for hotel and attempt to book When I book a hotel as valid signed in user Then I should see confirmation that my hotel is booked

BDD Cucumber @tags@iOS @Android @SMOKEFeature: Hotel Search and Book

Scenario: Search and book hotel as Sign In user Given I'm searching for hotel and attempt to book When I book a hotel as valid signed in user Then I should see confirmation that my hotel is booked

----- Meeting Notes (4/8/14 18:47) -----Tags @ feature level.applicable to all Scenarios, scenario outline12

BDD StepDefs//Spring context file@ContextConfiguration("classpath:cucumber.xml")

//hotel object gets input from Spring@Autowired private Hotel hotel;

@Given("^I'm searching for hotel and attempt to book$") public void search() {hotel.search(); }

----- Meeting Notes (4/8/14 18:59) -----Runtime it passes ios, Android13

Java code

public interface Hotel {void search();}// iOSpublic class IosHotelImpl implements Hotel {

@OverridePublic void search() {IosSearchScreen iosSearchScreenObj = new IosSearchScreen(getWebDriver());}// Androidpublic class AndroidHotelImpl implements Hotel {

@OverridePublic void search() {AndroidSearchScreen androidSearchScreenObj = new AndroidSearchScreen(getWebDriver());}

----- Meeting Notes (4/8/14 18:59) -----We saw cucumber, Spring config, Java code.

Missing part is StepDefs. 14

Screen Objects - iOS// iOS Screen Object

public class iOSSearchScreen extends AbstractScreen {

@FindBy(name = Search") private WebElement searchBtn; public void search() { searchBtn.click(); }

}

Screen Objects - Android// Android Screen object

public class AndroidSearchScreen extends AbstractScreen {

@FindBy(id= Search") private WebElement searchBtn;

public void search() { searchBtn.click(); }

}

Screen Objectspublic class AbstractScreen {

private final WebDriver webdriver;

public AbstractScreen(WebDriver webdriver) { PageFactory.initElements(webdriver, this); this.webdriver = webdriver; }

protected WebDriver getWebDriver() { return webdriver; }}

BDD StepDefs//Spring context file@ContextConfiguration("classpath:cucumber.xml")

//hotel object assigned by Spring@Autowired private Hotel hotel;

@Given("^I'm searching for hotel and attempt to book$") public void search() {hotel.search(); }

----- Meeting Notes (4/8/14 18:59) -----Runtime it passes ios, Android18

Dependency Injection using Spring FrameworkContext file - Cucumber.xml

----- Meeting Notes (4/8/14 18:47) -----Spring provides many features. One major one is DI. Easy to implement and integrate with this framework

19

Dependency Injection using Spring Framework

Cucumber-ios.xml

----- Meeting Notes (4/8/14 18:47) -----ios implementation

Also any user specifc data like user input for user creation

20

Dependency Injection using Spring Framework

Cucumber-android.xml

----- Meeting Notes (4/8/14 18:49) -----Lets look at what is in the HotelImpl.java class21

Managing Dependency3rd Party Jars

CucumberSpringReportingJunit / testng

Tests Jars

FeaturesStepDefsiOS-Screen-ObjectsAndroid-Screen-Objects

Hotwire Apps BDD architecture

Screen Objects (Objects representing screen / fragment)Appium server (Node.js)Apple Instruments with UI AutomationiPhone / iPad[Simulator / Device]APPJSONJS

Appium locator & toolsWebDriver Locators :IDNameXpathTools :Appium inspector (iOS)Uiautomatorviewer (Android)

Appium Sample Code Send Text and Tap @FindBy(name = "Email address") private WebElement emailAddress;

@FindBy(name = "Password") private WebElement password;

@FindBy(name = "Sign in") private WebElement signIn; public void enterSignIn(String emailAddress, String password) { this.emailAddress.clear(); this.emailAddress.sendKeys(emailAddress); this.password.clear(); this.password.sendKeys(password); this.signIn.click(); }

Sample Code Swipe functionalityprivate void swipeFunctionality(WebElement startPoint, WebElement endPoint) {

HashMap args = new HashMap(); double x1 = startPoint.getLocation().getX(); double y1 = startPoint.getLocation().getY(); double width1 = startPoint.getSize().getWidth(); double height1 = startPoint.getSize().getHeight(); args.put("touchCount", (double) 1); args.put("startX", (double) (x1 + width1) - 5); args.put("startY", (double) (y1 + height1 / 2));

double x2 = endPoint.getLocation().getX(); double y2 = endPoint.getLocation().getY(); double width2 = endPoint.getSize().getWidth(); double height2 = endPoint.getSize().getHeight(); args.put("touchCount", (double) 1); args.put("endX", (double) (x2 + width2) - 5); args.put("endY", (double) (y2 + height2 / 2));

args.put("duration", (double) 1); executeScript("mobile: swipe", args); }

public Object executeScript(String script, Object... args) { return ((JavascriptExecutor) getAppiumDriver()).executeScript(script, args); }

Sample code (contd.) if (checkInDate.equals(LocalDate.now().plusDays(1))) { LocalDate currentDate = LocalDate.now(); String currentMonth = new SimpleDateFormat("MMMM").format(currentDate.toDateTimeAtStartOfDay().toDate()); String currentDay = currentDate.dayOfMonth().getAsString(); String currentWeekName = currentDate.withDayOfWeek(currentDate.getDayOfWeek()).dayOfWeek().getAsText(); String currentCheckin = "S_Today, " + currentWeekName + ", " + currentMonth + " " + currentDay; WebElement currentElmt = getAppiumDriver().findElement(By.name(currentCheckin)); swipeFunctionality(currentElmt, checkOutElmt); } else if (checkInMonth.equals(checkOutMonth) || nextToCheckInMonth.equalsIgnoreCase(checkOutMonth)) { checkInElmt.click(); if (tapOrDrag.equalsIgnoreCase("tap")) { checkOutElmt.click(); } else if (tapOrDrag.equalsIgnoreCase("tap and drag")) { swipeFunctionality(checkInElmt, checkOutElmt); } else { swipeFunctionality(nextToCheckInElmt, checkOutElmt); } } else { checkInElmt.click(); if (tapOrDrag.equalsIgnoreCase("tap")) { fillCalendarMonth(checkOutMonth); checkOutElmt.click(); } else if (tapOrDrag.equalsIgnoreCase("tap and drag")) { WebElement middleElmt = findMiddleElement(checkInDate, checkInDay, checkInMonth); swipeFunctionality(checkInElmt, middleElmt); fillCalendarMonth(checkOutMonth); swipeFunctionality(middleElmt, checkOutElmt); } else { WebElement middleElmt = findMiddleElement(checkInDate, checkInDay, checkInMonth); swipeFunctionality(nextToCheckInElmt, middleElmt); fillCalendarMonth(checkOutMonth); swipeFunctionality(middleElmt, checkOutElmt); } }

iOS Demo

Native frameworksEspresso AndroidXcode UI testing - iOS

Espresso

Espresso is an open source Android test automat