Component Based Unit Testing ADF with Selenium
-
Upload
richard-olrichs -
Category
Technology
-
view
331 -
download
2
Transcript of Component Based Unit Testing ADF with Selenium
About Us
Richard Olrichs
MN
www.olrichs.nl
@richardolrichs
Wilfred van der Deijl
The Future Group
www.redheap.com
@wilfreddeijl
AgendaDemo: Selenium
Plain Selenium Examples
Page Objects
Demo: ADF Selenium
ADF Selenium Tools
Demo: Testing Your Bounded Taskflows
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 interactionVery flaky with modern apps
● Used in OTN Article (don’t do that)
Selenium v2 (aka WebDriver)
● Native events to drive browser
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 Toolsgithub.com/wvanderdeijl/adf-selenium
Two JDev 12c Projects:
● SeleniumTools - Library JAR● RichClientDemoTest - Sample JUnit tests against ADF 12c component 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@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());
}
Page Object
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());
}
ADF Component Object
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 withADF 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?
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 ObjectSeleniumTools
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 Page ObjectSeleniumTools
Selenium
CustomCode
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?
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 methodsfindAdfComponent uses (relative) JSF selectors
Acquiring ADF ComponentSeleniumTools
Selenium
CustomCode
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 Componentsimport com.redheap.selenium.component.AdfComponent;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
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 elementsSelenium Actions can interact with browser and mouseAdfComponent.waitForPpr waits for any PPR and complete javascript processing
SeleniumTools
Selenium
CustomCode
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?
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 componentComponent classes frequently use javascript to interact with componentsAdfComponent base class offers protected executeScript methodEvery component becomes a client component withoracle.adf.view.rich.automation.ENABLED=true in web.xml
Interacting with ADF ComponentsSeleniumTools
Selenium
CustomCode
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: AdfTablelong 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
Bounded Taskflow RecapJUnit Test your taskflows
Use TaskFlow Tester for isolated tests - java.net/projects/adf-task-flow-tester
PerceptualDiffMatcher - bit.ly/pdiffor look at more powerful Depicted at github.com/bslatkin/dpxdt
JaCoCo Code CoverageJUnit Rule to dump execution data - bit.ly/jacoco-ruleOptional reporter to write html report - bit.ly/jacoco-report
Browser of choice: Firefox, PhantomJS or any other...
Resources
github.com/wvanderdeijl/adf-seleniumwww.seleniumhq.org - mostly v1 docsseleniumhq.github.io/docs/ - new v2 docs
Screenshot Diff Assertion Violation
Tested application looks different during test compared to “known
good reference”