Date post: | 15-Apr-2017 |
Category: |
Software |
Upload: | nick-abalov |
View: | 3,441 times |
Download: | 0 times |
Selenium for Windows Phone & Desktop
Who am I?
2
Nikolai AbalovSoftware Development Engineer in Test at 2GIS
@nickab NickAb
Outline
3
• Background & motivation• What is Selenium, JsonWire Protocol & Appium• Windows Phone Automation
• Existing tools• Winium – Selenium for Windows• How it works• Quick start• Milestones
• Windows Desktop Automation• Existing tools• Winium – Selenium for Windows• How it works• Quick start
• Cross Platform Automation
4
Selenium“Free and open protocol for testing that has become a defacto standard”
Appium
6
• Selenium 2.0 → 3.0• W3C working draft• JsonWireProtocol
JsonWireProtocol
Over HTTPWebDriver
ImplementationSystem
under testMagic
Get element text (JSON Wire Example)
7
GET http://127.0.0.1:9999/session/AwesomeSession/element/2026335-‐1/text HTTP/1.1 ... Content-‐Type: application/json;charset=UTF-‐8 Connection: close Accept: application/json
HTTP/1.1 200 OK Content-‐Type: application/json;charset=UTF-‐8 Connection: close
{"sessionId":"AwesomeSession", "status":0, "value":"CodeFest"}
Appium
8
Platforms• iOS• Android• FirefoxOS
App types• Native• Hybrid
Why we love Selenium & Appium?
9
• Free and open-source• Cross platform• Great community• Simple and easy to use protocol• Client binding for all major programming languages
Winium
Windows Phone Automation
12
October 2010 Windows Phone 7
October 2011 Expensify • WindowsPhoneTestFramework (BDD, Native Apps)
October 2012 Windows Phone 8
March 2014 WinphoneDriver (Selenium, Native Apps, Silverlight, WP 8.0)
April 2014 Windows Phone 8.1 • MS Coded UI (Native Apps, Visual Studio Premium or higher)
May 2014 Forcedotcom • WinphoneDriver (Selenium, Web Apps)
June 2014 WinphoneDriver (updated for WP 8.1)
February 2015 Winium.StoreApps (Selenium, Native Apps, WP 8.1, Store Apps)
April 2015 Winium.StoreApps.CodedUi (Selenium, Native, Hybrid*, WP 8.1, Store Apps, Silverlight)
Winium for Store Apps
Features
15
• The only mobile WebDriver implementation that supports Native Windows Phone apps
• Compatible with JSON Wire Protocol• UI elements can be found by different locator types• File deployment• Gestures are supported (single touch)• Inspector
Limitations
16
• Emulators only (no device support)• Requires InnerServer to be embedded into the app under test*• One session at a time**
17
Tests
Winium.StoreApps.Driver
Emulator
JsonWireProtocol
Over HTTP
XDEVirtualMachine
API
Internal API
Over HTTPAutomationServer
App under test
How to start
18
• Prepare the app• Write tests• Run
Prepare the app
19
1. Add NuGet package Winium.StoreApps.InnerServer2. In MainPageOnLoaded (or anywhere on UI thread) initialize and
start server#if DEBUG AutomationServer.Instance.InitializeAndStart(); #endif // DEBUG
3. Make your app testable (assign automation names, ids, etc.)4. Build and package your appx
Write tests
20
Use Selenium or Appium bindings and write tests just like you would for web or iOS and Android
Session capabilities
21
dc = { 'deviceName': 'Emulator 8.1 WVGA 4 inch 512MB', 'app': r'C:\YorAppUnderTest.appx', 'files': { { 'C:\AppFiles\file1.png': 'download\file1.png', 'C:\AppFiles\file2.png': 'download\file2.png' } }, 'debugConnectToRunningApp': False }
Finding elements
22
id AutomationProperties.AutomationId
name AutomationProperties.Name
class name Fully qualified class name
tag name Fully qualified class name
xname x:Name
Winium Inspector
23
Acting on elements
24
element = driver.find_element_by_id('MyTextBox')
# get text value element.text # >> 'Send me some keys'
element.click()
# send keys to the element element.send_keys('Hello!'+Keys.ENTER)
Get value of any public property of element
25
# scalars and strings element.get_attribute('Width') # 300
# nested properties element.get_attribute('DesiredSize.Width') # 300
# other properties, serialized as JSON element.get_attribute('DesiredSize') # '{"Width":300.0,"Height":114.0,"IsEmpty":false}'
Touch
26
TouchActions(driver).flick_element(element, 0, 500, 100).perform()
TouchActions(driver).scroll(200,200).perform()
# create your own touch gesture ActionChains(driver) \ .click_and_hold() \ .move_by_offset(100, 100) \ .release().perform()
# We implement JSONWire Protocol actions API # Support for new Mobile WebDriver API will be added soon
Extended commands
27
# direct use of Windows Phone automation APIs app_bar_button = driver.find_element_by_id('GoAppBarButton') driver.execute_script('automation: InvokePattern.Invoke', app_bar_button)
list_box = driver.find_element_by_id('MyListBox') si = {'v': 'smallIncrement', 'count': 10} driver.execute_script('automation: ScrollPattern.Scroll', list_box, si)
# setting value of public property text_box = driver.find_element_by_id('MyTextBox') driver.execute_script('attribute: set', text_box, 'Width', 10) driver.execute_script('attribute: set', text_box, 'Background.Opacity', 0.3)
28
NewSession ExecuteScript MouseMoveTo
Close ClickElement MouseClick
Quit GetElementText MouseDown
GetPageSource GetElementAttribute MouseUp
FindElement IsElementDisplayed TouchSingleTap
FindElements GetElementLocation TouchScroll
FindChildElement SendKeysToElement TouchFlick
FindChildElements GetWindowSixe …
Screenshot GoBack
/2gis/Winium.StoreApps/wiki/Supported-Commands
Simple test
29
import unittest from selenium.webdriver import Remote
class TestMainPage(unittest.TestCase): desired_capabilities = {"app": "C:\\YorAppUnderTest.appx"}
def setUp(self): self.driver = Remote(command_executor="http://localhost:9999", desired_capabilities=self.desired_capabilities)
def test_button_tap_should_set_textbox_content(self): self.driver.find_element_by_id('SetButton').click() assert 'CARAMBA' == self.driver.find_element_by_id('MyTextBox').text
def tearDown(self): self.driver.quit()
Run
30
1. Start Winium.StoreApps.Driver.exe (download release from )2. Run tests as usual
Milestones
32
• Multiple sessions support• Windows 10 support• Refactor InnerServer and Driver communication• GPS, Network and Sensors simulation• Web and Hybrid apps supports• Multi-touch gestures
Winium.StoreApps.CodedUI
Features
35
• No modification of app under test required to automate it (Appium Rule 1)
• Runs on both Emulators and Devices• Compatible with JSON Wire Protocol• Already has limited support for Hybrid apps
Limitations
36
• Early prototype• Visual Studio Premium or higher (for CodedUI)• One session*
37
Tests
Winium.StoreApps.Driver
Emulator
JsonWireProtocol
Over HTTP
XDEVirtualMachine
API
App under test
vs.test.consoleCodedUI
Internal API
Windows Desktop Automation
Winium for Desktop
Features
42
• Automate native Windows Desktop app (WinForms, WPF, every app, that uses MS accessibility)
• Compatible with JSON Wire Protocol• Full access to desktop and UI• Protocol extensions for desktop specific elements
(Winium.Elements for C#)
Limitations
43
• Uses real mouse and keyboard events, i.e. you can’t run more than one session on same machine, or use mouse while tests are running
44
Tests
JsonWireProtocol
Over HTTP
Winium.Desktop.Driver
Winium.Cruciatus App under test
Desktop
UI Automation
Framework
Automating calculator
45
Scenario
1. Launch the calc.exe2. Select engineering mode3. Calculate "2^8"4. Close the calc.exe
Automating calc.exe (python bindings)
47
# setup dc = {'app': 'C:/windows/system32/calc.exe'} driver = Remote(command_executor='http://localhost:9999', desired_capabilities=dc) # test window = driver.find_element_by_class_name('CalcFrame') menu = window.find_element_by_id('MenuBar') view_menu_item = menu.find_element_by_name('View') view_menu_item.click() view_menu_item.find_element_by_name('Scientific').click()
window.find_element_by_id('132').click() # 2 window.find_element_by_id('97').click() # ^ window.find_element_by_id('138').click() # 8 window.find_element_by_id('121').click() # =
result = window.find_element_by_id('150').get_attribute('Name') assert '256' == result # teardown driver.close()
Automating calc.exe (C# bindings)
48
// setup var dc = new DesiredCapabilities(); dc.SetCapability("app", @"C:/windows/system32/calc.exe"); var driver = new RemoteWebDriver(new Uri("http://localhost:9999"), dc); // test var window = driver.FindElementByClassName("CalcFrame"); var menu = driver.FindElement(By.Id("MenuBar")); var viewMenuItem = menu.FindElement(By.Name("View")); viewMenuItem.Click(); viewMenuItem.FindElement(By.Name("Scientific")).Click();
window.FindElement(By.Id("132")).Click(); // 2 window.FindElement(By.Id("97")).Click(); // ^ window.FindElement(By.Id("138")).Click(); // 8 window.FindElement(By.Id("121")).Click(); // =
var result = windows.FindElement(By.Id("150")).GetAttribute("Name"); Assert.AreEqual("256", result); // teardown driver.Close();
Thank you!
Nikolai Abalov Gleb [email protected] [email protected]
/2gis/Winium
/2gis/Winium.StoreApps
/2gis/Winium.Desktop
/2gis/Winium.StoreApps.CodedUi
/2gis/winphonedriver
Cross Platform Automationwith Winium and Appium
Introduction
51
• We have mobile app for 3 major platforms• iOS• Android• Windows Phone
• We have similar interface for all platforms• We have separate dev and qa teams for each platform• We use Appium for iOS & Android, Winium for WP• Each team writes common test cases and reinvents the wheel
52
iOS Dev & QA Team Android Dev & QA Team WP Dev & QA Team
iOS4 UI tests Appium
Android4 UI tests Appium
WP4 UI tests Winium
53
iOS Dev & QA Team Android Dev & QA Team WP Dev & QA Team
Appium
v4 UI tests
Winium
What are benefits of common tests?
54
• No more wheel reinvention• Less code duplicity, easier to maintain• Better code quality and practices• Knowledge sharing• Systematic approach• Faster test development
Structure
55
v4-ui-testsClasses
• Interfaces• Components• Pages
• Android• Components• Pages
• iOS• Components• Pages
• WP• Components• Pages
ConfigTests
Language: Python Framework: Contesto Drivers: Appium, Winium
Interface sample
56
# coding: utf-‐8 from abc import abstractmethod
from classes.interfaces import ComponentMeta
class ISearchBar(object): __metaclass__ = ComponentMeta
@abstractmethod def open_search(self): """ :rtype: classes.interfaces.pages.search_page.ISearchPage """ pass
@abstractmethod def text(self): pass
Platform specific implementation
57
# coding: utf-‐8 from classes.android.components.component import Component from classes.android.helpers import get_android_text from classes.interfaces.components.search_bar import ISearchBar
class SearchBar(Component, ISearchBar): def open_search(self): from classes.android.pages.search_page import SearchPage self.element.click() return SearchPage(self.driver)
def text(self): return get_android_text(self.element)
def is_displayed(self): return self.element.is_displayed()
Conditional entrypoint
58
from config import config, platform, Platforms
# In languages like C# or Java conditional import will be replaced with some kind of factory # For python I would also recommend factory pattern instead of magic imports if platform == Platforms.Android: from classes.android.base_case import AndroidTestCase as TestCase from classes.android.base_case import AndroidWithPreloadedTestCase as WithPreloadedTestCase
elif platform == Platforms.WindowsPhone: from classes.wp.base_case import WindowsPhoneTestCase as TestCase from classes.wp.base_case import WindowsPhoneWithPreloadedTestCase as WithPreloadedTestCase
elif platform == Platforms.iOS: from classes.ios.base_case import IosTestCase as TestCase from classes.ios.base_case import IosWithPreloadedTestCase as WithPreloadedTestCase
else: from interfaces.base_cases import WithPreloadedTestCase raise LookupError('Unknown platform %s' % platform)
Initial setup
59
Installed python on each node
Setup 3 nodes:1. OS X with Xcode, iOS Simulators and Appium2. Ubuntu with Android SDK, setup emulator and Appium3. Windows 8.1 with Windows Phone SDK and Winium
Running tests
60
# Common setup (language specific) pip install -‐r requirements.txt
# Android on Ubuntu pip install -‐r requirements-‐android.txt PLATFORM=Android nosetests tests -‐s
# iOS on OS X PLATFORM=iOS nosetests tests -‐s
# Windows Phone on Windows set PLATFORM=WindowsPhone && nosetests tests -‐s
# Or run tests for all 3 platforms from single machine that is connected to 3 platform specific nodes