47
Improving Your Selenium WebDriver Tests Roy de Kleijn Technical Test Consultant Email: [email protected] Twitter: @TheWebTester Website: http://www.rdekleijn.nl Github: https:// github.com/roydekleijn

Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Embed Size (px)

Citation preview

Page 1: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Improving Your Selenium WebDriver

Tests

Roy de KleijnTechnical Test ConsultantEmail: [email protected]: @TheWebTesterWebsite: http://www.rdekleijn.nlGithub: https://github.com/roydekleijn

Page 2: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Question #1

What makes your Selenium WebDriver tests suck?

Page 3: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Answer #1

Depending on third-party data

Synchronization issues

Cross-browser issues

Hard to locate elements

testdata

Slow feedback cycle

Flaky tests

High maintenance costs

Page 4: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Lack of confidence

Results in …

Page 5: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Contents• Introduction• Element locator tips & tricks• Implementing the Page Object Model• Utilize Data Objects• Handle synchronization• Speed-up and stabilize your tests (demo)• What we have learned

We will start with an actual Page Object Model implementation today

Page 6: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Maintenance testM

aint

enan

ce e

ffort

Time

Start

with re

cord an

d playbac

k

Convert

recorded te

sts in

to code

Awesome, it

works

! Let’s

create

more UI te

sts Reality: code ends up into unmaintainable spaghetti

Design patt

erns applie

d

Implement fe

atures t

o mak

e tests

robust

wish

Page 7: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Testing Pyramid

unit

UI

API

feed

back

-cyc

le

- Extremely fast- Smallest units of the application / isolates failure- Executed during build time- No dependency on data

- Extremely slow- Requires running application- Will change frequently- Dependency on data

- Fast- Covering boundary conditions- Start early in SD process - Requires running application- (some) dependency on data

Page 8: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Mock External Interfaces

application

Interface 1

Interface 2

Interface 3

application

Interface 1

Interface 2

Interface 3m

ock

Page 9: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Contents• Introduction• Element locator tips & tricks• Implementing the Page Object Model• Utilize Data Objects• Handle synchronization• Speed-up and stabilize your tests (demo)• What we have learned

We will start with an actual Page Object Model implementation today

Page 10: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Question #2

What is wrong with these locators?

#1.//*[@id='wx-header-wrap']/div/div/div/div[2]/div[2]/div/section/div/form/input

#2.//*[@id='gnav-header-inner']/div/ul/li[2]/a

Page 11: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Answer #2

They contain too much information about the location

Page 12: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Closer look #1

Page 13: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Closer look #1.//*[@id='wx-header-wrap']/div/div/div/div[2]/div[2]/div/section/div/form/input

What if the location of this element will change over time?

It can be written like this: input[class = ‘input--search’]Orinput.input—searchOrinput[name = ‘search’]

Page 14: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Closer look #2

Page 15: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Closer look #2.//*[@id='gnav-header-inner']/div/ul/li[2]/a

What if the order of the links will change over time ?

It can be written like this: a[id=register]Ora#register

Page 16: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Attribute selectorscss xpath

Equals e[a=v] //e[@a=v]

Contains e[a*=v] //e[contains(@a, ‘v’)]

Starts-with e[a^=v] //e[starts-with(@a, ‘v’)]

Ends-with e[a$=v] //e[ends-with(@a, ‘v’)]

Page 17: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

AngularJS - elements

• Different way of locating elements• Binding• Model• Repeat

• ngWebDriver library (create by Paul Hammant)• https://github.com/paul-hammant/ngWebDriver• Logic from Protractor project

Page 18: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

• Enable debug info• Call angular.reloadWithDebugInfo(); in your browser debug console

• Execute the following snippet to reveal all the elements:

var bindings = document.getElementsByClassName('ng-binding');for (var i = 0; i < bindings.length; ++i) {var bindingName = angular.element(bindings[i]).data().$binding[0].exp ||angular.element(bindings[i]).data().$binding; console.log(bindingName.toString()); console.log(bindings[i]);}

Page 19: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Contents• Introduction• Element locator tips & tricks• Implementing the Page Object Model• Utilize Data Objects• Handle synchronization• Speed-up and stabilize your tests (demo)• What we have learned

We will start with an actual Page Object Model implementation today

Page 20: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Problems that arise

• Unmaintainable• Unreadable test scripts• Creation of test scripts is time consuming• Code duplication

Page 21: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

From problem to solution

Page 22: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Solution

Each page contains only a part of the total functionality available on the website

Put page specific functionality in a class with a corresponding name

Page 23: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Step-by-step plan

1. Identify necessary WebElements2. Create a class3. Define WebElements in corresponding classes4. Model the functionality of a page into methods5. Model the page flow by setting returntypes

Page 24: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Identify necessary WebElements

Page 25: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Create a class

A class with the name of the page extending from LoadableComponent

public class HomePage extends LoadableComponent<HomePage> { private WebDriver driver;

public HomePage(WebDriver driver) { this.driver = driver; PageFactory.initElements(driver, this); }

Page 26: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Define WebElementsOn class level (above the methods)

@FindBy(css = "a.login")

private WebElement loginLink;

Page 27: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Model the functionality

public LoginPage clickOnLoginLink() { loginLink.click(); return new LoginPage(driver); }

Page 28: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Model the page flow

• Prerequisite:• Multiple pages are modelled

• Modify returntype• The returntype is the name of the page (class) where you are navigating

towards• Use the current class name, if you stay on the same page

Page 29: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Model the page flow

public LoginPage clickOnLoginLink() { loginLink.click(); return new LoginPage(driver); }

Returning page

Page 30: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Contents• Introduction• Element locator tips & tricks• Implementing the Page Object Model• Utilize Data Objects• Handle synchronization• Speed-up and stabilize your tests (demo)• What we have learned

We will start with an actual Page Object Model implementation today

Page 31: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Data Objects final CustomerAccount account = new CustomerAccount.CustomerAccountBuilder("[email protected]","1qazxsw2").build();

Access data:account.getEmail()

account.getPassword()

Page 32: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Data Objects - Complex final Order order = new Order.OrderBuilder()//

.withInvoiceAddress(new Address.AddressBuilder("abc street", "1234ab").build())// .withShippingAddress(new Address.AddressBuilder("shipstreet”, "4321ab").withCountry("The Netherlands").build())//

.build();

// Retrieve data from the objectSystem.out.println(order.getInvoiceAddress().getStreet());

System.out.println(order.getShippingAddress().getCountry());

Page 33: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Contents• Introduction• Element locator tips & tricks• Implementing the Page Object Model• Utilize Data Objects• Handle synchronization• Speed-up and stabilize your tests (demo)• What we have learned

We will start with an actual Page Object Model implementation today

Page 34: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Synchronization issues

• Browser has to start• Page has to load• AJAX request need to be finished• Or, loader should be gone before we can continue

Page 35: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

What NOT to do …

NEVER, use Thread.sleep();

• It will probably make your test unnecessary slow• You never know if you wait exactly long enough

Page 36: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

What to do…

• WebDriver build in wait mechanisms• implicitlyWait: poll till element is present• setScriptTimeout: time to wait for an asynchronous script to finish• pageLoadTimeout: time to wait for a page load to complete

• ngWebDriver• waitForAngularRequestsToFinish – wait for outstanding angular requests

• Custom (gist)• checkPendingRequests – wait for all HTTP requests to be finished

Page 37: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Example 1

Wait for element to be clickable

@Testpublic void waitForElementToBeClickable() {

new WebDriverWait(driver, 20,100) //.until(ExpectedConditions.elementToBeClickable(

By.cssSelector("a.login")));}

Page 38: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Example 2

Wait for loader to be invisible

@Testpublic void waitForElementNotToBeVisable() {

new WebDriverWait(driver, 20, 100) //.until(ExpectedConditions.invisibilityOfElementLocated(

By.cssSelector("loader")));}

Page 39: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Contents• Introduction• Element locator tips & tricks• Implementing the Page Object Model• Utilize Data Objects• Handle synchronization• Speed-up and stabilize your tests (demo)• What we have learned

We will start with an actual Page Object Model implementation today

Page 40: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Speed-up and stabilize your tests Windows 7

IEFF

Chrome

Windows vistaIEFF

UbuntuFF

Opera

Mac OSFF

ChromeOpera

Nodes

Hub

Specification

HUB

Test Scripts

Page 41: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Docker Selenium

• Disposable Selenium Grid (in seconds)• Autoscaling features

• https://hub.docker.com/r/selenium/

Page 42: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Docker-composeseleniumhub: image: selenium/hub ports: - 4444:4444firefoxnode: image: selenium/node-firefox environment: SCREEN_WIDTH: 2880 SCREEN_HEIGHT: 1800 ports: - 5900 links: - seleniumhub:hub

chromenode: image: selenium/node-chrome environment: SCREEN_WIDTH: 2880 SCREEN_HEIGHT: 1800 ports: - 5900 links: - seleniumhub:hub

Page 43: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Docker commands

docker-compose up –d-d: Run containers in the background--force-recreate: Recreate containers entirely

Autoscaling:docker-compose scale firefoxnode=5 chromenode=1

Page 44: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

In practice

Implement or extend the Page Object Model

• Website• url: http://demo.technisch-testen.nl

• Source• Github: https://github.com/roydekleijn/webdriver-workshop

Page 45: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Contents• Introduction• Element locator tips & tricks• Implementing the Page Object Model• Utilize Data Objects• Handle synchronization• Speed-up and stabilize your tests (demo)• What we have learned

We will start with an actual Page Object Model implementation today

Page 46: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

What we have learned today

Depending on third-party data

Cross-browser issues

Hard to locate elements

testdata

Slow feedback cycle

Flaky tests

High maintenance costs

Synchronization issuesAvoid Thread.sleep() or other hardcoded

waits

Utilize Page Object Model

id > name > css > xpath > angular

Mock interfaces

Run tests in parallel

Mock interfaces

Mock interfaces, setup clean environments,

implement page object model

Page 47: Improving Your Selenium WebDriver Tests - Belgium testing days_2016

Thank you…

Roy de KleijnTechnical Test ConsultantEmail: [email protected]: @TheWebTesterWebsite: http://www.rdekleijn.nlGithub: https://github.com/roydekleijn