extensible selenium framework

Post on 10-Apr-2015

4.516 Views

Category:

Documents

5 Downloads

Preview:

Click to see full reader

DESCRIPTION

The Strategies and Concepts of Building a Flexible and Extensible Test Framework Around Selenium

TRANSCRIPT

Building a Flexible & E t ibl F kExtensible Framework Around Selenium

Apple Chow

Santiago Etchebehere

Outline

• Our Challengesg

• Our Design Decisions

• Framework ArchitectureFramework Architecture

• Framework Features

• Our ExperienceOur Experience

• Q & A

Our Challenges

• Frequent Requirement Changesq q g

• Complex Web UI

• Multiple Projects to Testp j

• Limited Resources

• Browsers, PlatformsBrowsers, Platforms

Design Decisions

• Simplicity– Isolating application actions – Utilities for filling forms– Utilities for interacting with tables– AJAX handling utilities– Uniform way to access UI elements– Uniform way to access UI elements

• Flexibility– Grouping of test cases p g– Custom place holders (configuration & data)– Ability to support non-standard UI elements

Design Decisions

• Maintainability/Configurabilityy g y– Externalized configuration

– Reduce data duplication

• Data driven tests– Execute same test against multiple datasets

R d l t t t d d t– Randomly generate structured data

Selected Tools

• Selenium RC (http://www.openqa.org/selenium/)( p p q g )

– Locators

– WaitForCondition xpath://img[@alt=“Google”]

– getEval Name: qDOM: document.f.q

When page first loads Now readyWhen page first loads… Now ready…

Name: btnGselenium.waitForCondition("

selenium.isElementPresent('orderBtn')

&& selenium.isEditable('orderBtn')“,

timeout);

Selected Tools

• TestNG (http://testng.org/doc/index.html)

@DataProvider(name ="customerDataProvider")public Object[][] customerProvider() {...

}

( p g g )

– @Test configurations

– Data providers}

@Test(dataProvider = "customerDataProvider")

public void test(String id String name) {

• Firebug

public void test(String id, String name) {...

}

Framework Architecture

Application Configuration GUI Map Data Map

UI Objects SeleniumHelper Util DataGenerator

Base TestBase Client

Application-Specific Client

Application-Specific Test ClassUses

Application Config

<appconfig><parameters>< t l>htt </ t l><protocol>http</protocol><host>www.google.com</host><port></port>

<pagesXml>googlesearch/uimap.xml</pagesXml>j tX l l h/d t l / j tX l<projectXml>googlesearch/datamap.xml</projectXml>

<browserType>FIREFOX</browserType><browserVersion>2.0</browserVersion><timeout>300000</timeout>/</parameters>

</appconfig>

UI Object

• UI Element Abstraction

• read/write interface

public class TextUIObject implements UIObject{

public String read() {

return helper.getText(getLocator())

}}

public void write(String value) {

helper.type(getLocator(), value);

}

}

UI Map

<page name="searchForm"> < i l t ><uielements>

<uiobject name="search.query" type="text"><locator>q</locator>

</uiobject><uiobject name="search.button“ type="button">

<locator>btnG</locator></uiobject>

</uielements></page>

Common vs. Test-case Data

<category name="search"><data name="defaultSearch"><properties><prop name="search.query">United States</prop><prop name="search.button"/>

</properties></data>

references and o errides</category> references and overrides

<testcase id="googleSearch001"><dataset name="searchSet001"><dataref name="search001Query" ref="search.defaultSearch">

<prop name="search query">Argentina</prop><prop name="search.query">Argentina</prop></dataref>

</dataset></testcase>

UI Object and Data Mapping

<page name="searchForm"><data name=“searchData"><properties>

<prop name="search.query">United States</prop>

<prop name="search.button"/>

<page name= searchForm > <uielements><uiobject name="search.query"type="text"><locator>q</locator>

</uiobject> p p /</properties></data>

</uiobject>

<uiobject name="search.button"type="button”><locator>btnG</locator>

</ i bj t></uiobject></uielements>

</page>

…seleniumHelper.fillForm(“searchForm”, “searchData”);…

Application Client

• Contains methods to abstract interaction with your application.

• Uses Selenium (SeleniumHelper) to emulate the user action with the browser, using information from configuration files.

• Simplifies test case writing.

Application Test

• Implements the test cases by feeding the client methods with test case specific data.

• Uses Client's high level• Uses Client s high level method to implement the tests.

V ifi th t t t h• Verifies the output matches the expected result.

Test Case flow

Test Case flow

Test Case flow

Test Case flow

GoogleSearch Example

• Clients (GoogleSearchClient)

• Tests: hierarchy (e.g. GoogleSearchTest)

BaseClient BaseTest

G l S hCli t

BaseClient

Uses

BaseTest

G l S hT tGoogleSearchClient Uses GoogleSearchTest

... public void basicSearchTest(DataSet dataset){assertNotEmpty(client.basicSearch(

dataSet.getDataObject("searchData"));...

...

public TableObject basicSearch(data);

public TableObject advancedSearch(data);

...

Advanced Features

• AJAX Handling Utilities

• Custom UI Objects & Decorators

• Table Objects j

• Placeholders

• Data Generator

• Database Support

AJAX Handling (Loaded Condition)

<page name="iGoogle"><page name="search"><loaded-condition><loaded-condition> selenium.isElementPresent("q") &&selenium.isElementPresent("btnG")

</loaded-condition>…

100100

…seleniumHelper.waitForPageToLoad(“iGoogle.search”);…

AJAX Handling (Reload Trigger)

<page name="searchResults"><loaded-condition> ... </loaded-condition><uiobject name="nextLink" type="anchor" reloadTrigger="searchResults">

<locator>//a[text()='Next']</locator>ocato //a[te t() e t ] / ocato...

Custom UI Object

<uiobject name="elapsedTime"

type="SuggestTextBox">gg<locator>q</locator>

...

public class SuggestTextBox extends AbstractUIObject {public class SuggestTextBox extends AbstractUIObject {

...

public void write(SeleniumHelper helper, String value) {

for (char c : value.toCharArray()) {for (char c : value.toCharArray()) {

helper.type(this.getLocator(), c);

helper.wait(1000);

}

}

...

UI Object Decorators

<uiobject name="creditCardNumber" type="text"><locator>...</locator>

bli l BlurDecorator t d UIObj tD t {

<decorator>BlurDecorator</decorator>

...

public class BlurDecorator extends UIObjectDecorator {

...

public void write(String value) {

decoratedObject.write(value);

selenium.fireEvent(decoratedObject.getLocator(),"blur");

}

Table Object

<table name="questionsTable" ><locator>//table[@id='questions']</locator>

<uiobject name="unreadQuestions" type="img"><locator>tr[${rownum}]/td[2]/img</locator>

</uiobject>

<uiobject name=“subject" type="anchor"><l t >t [${ }]/td[3]/ </l t ><locator>tr[${rownum}]/td[3]/a</locator>

...

...

TableObject questions = new TableObject("questionsTable");

Map<String, String> firstRow = questions.getRow(1);String subject = questions.readCell(1,3);questions writeCell(1 "subject");questions.writeCell(1, subject );...

Placeholders

<appconfig>...• Configuration ...

<host>${sys.testHost}</host><user>${env.USER_NAME}<user>

...</appconfig>

• UI Object

• Data

...<locator>//div[@id='results']/span[${paginationResultNum}]</locator>

......

<data name=“userProfile"><properties>

< “ “> ${ti t }</ ><prop name=“username“>user_${timestamp}</prop> <prop name="name">${dataGenerator.string(10)}</prop><prop name="email">${dataGenerator.email}</prop><prop name="age">${dataGenerator.regex([1..9][0..9])}</prop>

</properties>/</data>

Automation Process

1. Define application specific settings (e.g. application URL, browser)

2. Define UI elements map

3. Implement an application client to abstract application actions

4. Define common and test case specific data

5. Implement TestNG test cases that map to test case repository

Our Experience

• UI Changes

Location:L ti

Before After

UI Changes

Location:Location:

<uiobject name="location" type="text"><locator>location</locator>

<uiobject name="location" type="select"><locator>location</locator><locator>location</locator>

...<locator>location</locator>

...

UIObject location = page.getUIObject("location");

helper.write(location, countryName);}

Our Experience

• Custom UI ObjectCustom UI Object

public class RandomMultiSelectionUIObject extends SelectableUIObject {public String write(String count) {// Generate a list of random values from the possible options. String[] posibleOptions = helper.getSelectOptions(locator);List<String> values = dataGenerator.takeFromList(

A Li t( ibl O ti ) t)Arrays.asList(posibleOptions),count);

...super.write(selectedOptions.toString());

} ...

Our Experience

• i18n Test Data

<testcase id="test_001"><dataset name="usData"><dataref name="criteria" ref="contact.defaultSearch"/>

</d t t>

i18n Test Data

</dataset><dataset name="chineseData"> <dataref name="criteria" ref="contact.defaultSearch"/>

<prop name="keyword">廣告服務</prop></dataref>

</dataset></testcase>

@Test(dataProvider="searchDataProvider")

@Testcase(id="test_001")

void testSearch(DataSet set) {

TableObject resutlsTableObject resutls =

getClient().search(set.getDataObject("criteria"));

Our Team

• Special thanks to:Special thanks to:– Albert Chen

– Alejandro Bolognaj g

– Ariel Rodriguez

– Nicolas Frontini

– Raul Bajales

– Andrew Salamatov

Q & A

top related