View
504
Category
Embed Size (px)
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
