Sei sulla pagina 1di 42

ADF and Selenium

Component Based Unit Testing

About Us
Richard Olrichs

Wilfred van der Deijl

MN

The Future Group

www.olrichs.nl

www.redheap.com

@richardolrichs

@wilfreddeijl

Agenda
Demo: Selenium
Plain Selenium Examples
Page Objects
Demo: ADF Selenium
ADF Selenium Tools
Demo: Testing Your Bounded Taskflows

Selenium 101 Demo

Selenium 101
public void simpleTest() {
WebDriver driver = new FirefoxDriver();
driver.get("http://google.com/?hl=en");
WebElement searchBox =
driver.findElement(name("q"));
searchBox.sendKeys("adf selenium");
searchBox.submit();
}

Selenium History
Selenium v1

Uses JavaScript injection to emulate user interaction


Very flaky with modern apps

Used in OTN Article (dont do that)

Selenium v2 (aka WebDriver)

Native events to drive browser

Page Objects

Page Objects
Martin Fowler:
It should provide an interface that's easy to
program to and hides the underlying
widgetry in the window
Source: martinfowler.com/bliki/PageObject.html

Also advocated by Selenium team

ADF Selenium Tools

ADF Selenium Tools


github.com/wvanderdeijl/adf-selenium
Two JDev 12c Projects:

SeleniumTools - Library JAR


RichClientDemoTest - Sample JUnit tests against ADF 12c component demo

ADF Selenium Demo

Basic JUnit Example


@Test
public void testHover() {
CalendarDemoPage page = pages.goHome();
AdfCalendar calendar = page.findCalendar();
calendar.hoverActivityInView(0);
assertEquals("NOTE: This popup is for demo purposes only;...",
page.findPopupNote().getValue());
}

Basic JUnit Example


Page Object

@Test
public void testHover() {
CalendarDemoPage page = pages.goHome();
AdfCalendar calendar = page.findCalendar();
calendar.hoverActivityInView(0);
assertEquals("NOTE: This popup is for demo purposes only;...",
page.findPopupNote().getValue());
}

Basic JUnit Example


ADF Component Object

@Test
public void testHover() {
CalendarDemoPage page = pages.goHome();
AdfCalendar calendar = page.findCalendar();
calendar.hoverActivityInView(0);
assertEquals("NOTE: This popup is for demo purposes only;...",
page.findPopupNote().getValue());
}

Basic JUnit Example


@Test
public void testHover() {
CalendarDemoPage page = pages.goHome();
AdfCalendar calendar = page.findCalendar();
calendar.hoverActivityInView(0);
assertEquals("NOTE: This popup is for demo purposes only;...",
page.findPopupNote().getValue());
}

Interact with
ADF Component

Basic JUnit Example


@Test
public void testHover() {
CalendarDemoPage page = pages.goHome();
AdfCalendar calendar = page.findCalendar();
calendar.hoverActivityInView(0);
assertEquals("NOTE: This popup is for demo purposes only;...",
page.findPopupNote().getValue());
}

Test Assertion

Acquiring ADF Page Object


@Test
public void testHover() {
CalendarDemoPage page = pages.goHome();
AdfCalendar calendar = page.findCalendar();
calendar.hoverActivityInView(0);
assertEquals("NOTE: This popup is for demo purposes only;...",
page.findPopupNote().getValue());
}

How to start browser?


How to navigate to this page?

Acquiring ADF Page Object

SeleniumTools
Selenium
CustomCode

public class CalendarTest {


@ClassRule
public static WebDriverResource driver = new FirefoxDriverResource();
WebDriverResource starts (and stops) a web browser to run the tests
@ClassRule: invoke JUnit rule once per test class
@Rule: invoke JUnit rule for each test method

Acquiring ADF Page Object

SeleniumTools
Selenium
CustomCode

public class CalendarTest {


@ClassRule
public static WebDriverResource driver = new FirefoxDriverResource();
@Rule
public PageProvider<CalendarDemoPage> pages =
new PageProvider(CalendarDemoPage.class, PAGE_URL,
driver.getDriver());
PageProvider takes a WebDriver (browser) and knows how to navigate to a URL
and instantiate a Page Object
@Rule triggers provider for each test so we start fresh

Acquiring ADF Component


@Test
public void testHover() {
CalendarDemoPage page = pages.goHome();
AdfCalendar calendar = page.findCalendar();
calendar.hoverActivityInView(0);
assertEquals("NOTE: This popup is for demo purposes only;...",
page.findPopupNote().getValue());
}

How does a Page Object locate components?

Acquiring ADF Component

SeleniumTools
Selenium
CustomCode

import com.redheap.selenium.component.AdfCalendar;
import com.redheap.selenium.page.Page;
public class CalendarDemoPage extends Page {
public AdfCalendar findCalendar() {
return findAdfComponent("dmoTpl:cal");
}
com.redheap.selenium.page.Page base class offers protected utility methods
findAdfComponent uses (relative) JSF selectors

Interacting with ADF Components


How did we implement
@Test
component methods?
public void testHover() {
CalendarDemoPage page = pages.goHome();
AdfCalendar calendar = page.findCalendar();
calendar.hoverActivityInView(0);
assertEquals("NOTE: This popup is for demo purposes only;...",
page.findPopupNote().getValue());
}

Interacting with ADF Components


import com.redheap.selenium.component.AdfComponent;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;

SeleniumTools
Selenium
CustomCode

public class AdfCalendar extends AdfComponent {


public void hoverActivityInView(int index) {
WebElement element = findAllActivitiesInView().get(index);
// move mouse to element and wait for ADF to detect hover
new Actions(getDriver()).moveToElement(element).pause(1000).perform();
waitForPpr();
}
}

Component class encapsulates interaction with HTML elements


Selenium Actions can interact with browser and mouse
AdfComponent.waitForPpr waits for any PPR and complete javascript processing

Interacting with ADF Components


@Test
public void testHover() {
CalendarDemoPage page = pages.goHome();
AdfCalendar calendar = page.findCalendar();
calendar.hoverActivityInView(0);
assertEquals("NOTE: This popup is for demo purposes only;...",
page.findPopupNote().getValue());
}

How did we implement


component methods?

Interacting with ADF Components

SeleniumTools
Selenium
CustomCode

import com.redheap.selenium.component.AdfComponent;
public class AdfOutputText extends AdfComponent {
public Object getValue() {
return executeScript("var cmp=AdfPage.PAGE.findComponentByAbsoluteId(arguments[0]);"
+ "return cmp.getValue()",
getClientId());
}
}

CalendarDemoPage.findPopupNote returns AdfOutputText component


Component classes frequently use javascript to interact with components
AdfComponent base class offers protected executeScript method
Every component becomes a client component with
oracle.adf.view.rich.automation.ENABLED=true in web.xml

Selenium Tools Component Classes

Re-use a lot of logic that would otherwise live in Page Objects


Rely heavily on ADF JavaScript API
All extend from AdfComponent

click(), contextClick(), doubleClick()


dragAndDropTo(AdfComponent target)
findAdfComponent(String childId)
isDisabled(), isDisplayed()
scrollIntoView()
and a few more

Component Class Example: AdfTable


long getRowCount()
findAdfComponent(String child, int row)
scrollToRowIndex(int row)
discloseRowDetail(int row)
List<Integer> getDisclosedRows()
selectRow(int row)
selectToRow(int row)
selectAdditionalRow(int row)
... and all AdfComponent methods

Testing Your Bounded Taskflows

Bounded Taskflow Recap


JUnit Test your taskflows
Use TaskFlow Tester for isolated tests - java.net/projects/adf-task-flow-tester
PerceptualDiffMatcher - bit.ly/pdiff
or look at more powerful Depicted at github.com/bslatkin/dpxdt
JaCoCo Code Coverage
JUnit Rule to dump execution data - bit.ly/jacoco-rule
Optional reporter to write html report - bit.ly/jacoco-report
Browser of choice: Firefox, PhantomJS or any other...

Resources

github.com/wvanderdeijl/adf-selenium
www.seleniumhq.org - mostly v1 docs
seleniumhq.github.io/docs/ - new v2 docs

Demo shots
(reference material)

Example Test

Start test in Taskflow Tester

Basic assertions

Compare screenshot

Taskflow running in
Taskflow Tester

Validation Error
triggered by test

JUnit Test Runner in JDeveloper

JaCoCo Code Coverage Report

Not all paths tested


JaCoCo Code Coverage
shows this method wasnt
covered in test

Screenshot Diff Assertion Violation

Tested application looks different


during test compared to known
good reference

Known good
reference

Actual screenshot
during test

Diffs indicated

Potrebbero piacerti anche