Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Breaking the limits_of_page_objects

278 views

Published on

Munich Selenium Meetup 2017-06-22

Published in: Software
  • Be the first to comment

  • Be the first to like this

Breaking the limits_of_page_objects

  1. 1. Breaking the Limits of Page Objects Robert Bossek robert.bossek@qualityminds.de
  2. 2. . Software Architecture 1. Enterprise Architecture 2. Security Architecture & IAM 3. Application Architecture Testing Essentials 1. Test Design 2. Test Automation 3. Test Management 4. Test Data Environments 1. DevOps 2. Oracle 3. Technical Architecture Agile Testing 1. Test Coaching 2. Construction and Maintenance of the Regression Test Suite 3. E2E Test Management Requirements Engineering 1. Agile RE 2. RE Essentials 3. Testability Mobile Testing 1. Mobile Testing Strategy 2. Mobile Test Automation 3. Mobile Experience
  3. 3. Content Management System • commercial CMS tool • customized features • individual components • various configurations • various combinations • various user flows • test framework:
  4. 4. Basic Selenium Test • Selenium methods are accessed directly from the test case • Page elements are addressed directly in the test case <?php class LoginCest { public function loginTest(SeleniumWebDriver $I) { $I->amOnPage('http://www.payback.mx'); $I->fillField(['css' => 'input#cardnumber'], '5010961962'); $I->fillField(['css' => 'input#pin'], '1234'); $I->click(['css' => 'input[type="submit"]']); $I->see('Welcome'); } }
  5. 5. Simple Page Object • Page elements shall be encapsulated in a Page Object • reusable • maintainable <?php class LoginPage { public function getUrl(): string { return 'http://www.payback.mx'; } public function getCardnumberField(): array { return ['css' => 'input#cardnumber']; } public function getPinField(): array { return ['css' => 'input#pin']; } public function getLoginButton(): array { return ['css' => 'input[type="submit"]']; } }
  6. 6. Simple Page Object <?php class LoginCest { public function loginTest(SeleniumWebDriver $I) { $loginPage = new LoginPage(); $I->amOnPage($loginPage->getUrl()); $I->fillField($loginPage->getCardnumberField(), '5010961962'); $I->fillField($loginPage->getPinField(), '1234'); $I->click($loginPage->getLoginButton()); $I->see('Welcome'); } public function tryToLoginWithWrongPinTest(SeleniumWebDriver $I) { $loginPage = new LoginPage(); $I->amOnPage($loginPage->getUrl()); $I->fillField($loginPage->getCardnumberField(), '5010961962'); $I->fillField($loginPage->getPinField(), ‘4321'); $I->click($loginPage->getLoginButton()); $I->dontSee('Welcome'); } } • Page elements shall be encapsulated in a Page Object • reusable • maintainable • Selenium methods are still accessed directly from the test case
  7. 7. Simple Page Object <?php class LoginCest { public function loginTest(SeleniumWebDriver $I) { $loginPage = new LoginPage(); $I->amOnPage($loginPage->getUrl()); $I->click($loginPage->getEmailToggle()); $I->waitForElementVisible($loginPage->getCardnumberToggle()); $I->fillField($loginPage->getEmailField(), ‘user42@test.it'); $I->fillField($loginPage->getPinField(), '1234'); $I->click($loginPage->getLoginButton()); $I->see('Welcome'); } ... } • individual special case handling directly in test case • danger of • code duplication • differing/unstable handling • losing business case focus
  8. 8. Advanced Page Object <?php class LoginPage { private $webDriver; public function __construct(SeleniumWebDriver $webDriver) { $this->webDriver = $webDriver; } public function toggleToEmail() { $I = this->webDriver; $I->click($this->getEmailToggle()); $I->waitForElementNotVisible($this->getEmailToggle()); $I->waitForElementVisible($this->getCardnumberToggle()); } public function toggleToCardnumber() { $I = this->webDriver; $I->click($this->getCardnumberToggle()); $I->waitForElementNotVisible($this->getCardnumberToggle()); $I->waitForElementVisible($this->getEmailToggle()); } ... • Selenium methods shall also be encapsulated in the Page Object • single source of responsibility • higher stability • test driver must be passed to the Page Object
  9. 9. Advanced Page Object ... public function fillCardnumberField(string $cardnumber) { ... } public function fillEmailField(string $email) { ... } public function fillPinField(string $pin) { ... } public function clickLoginButton() { ... } public function loadPage() { ... } private function getUrl(): string { ... } private function getCardnumberField(): array { ... } private function getEmailField(): array { ... } private function getPinField(): array { ... } private function getLoginButton(): array { ... } private function getCardnumberToggle(): array { ... } private function getEmailToggle(): array { ... } } • Selenium methods shall also be encapsulated in the Page Object • single source of responsibility • higher stability • test driver must be passed to the Page Object • Page elements are hidden in the Page Object • prevents inproper usage • maintainable
  10. 10. Advanced Page Object <?php class LoginCest { public function loginTest(SeleniumWebDriver $I) { $loginPage = new LoginPage($I); $loginPage->loadPage(); $loginPage->toggleToEmail(); $loginPage->fillEmailField('user42@test.it'); $loginPage->fillPinField('1234'); $loginPage->clickLoginButton(); $I->see('Welcome'); } } • Selenium methods shall also be encapsulated in the Page Object • single source of responsibility • higher stability • test driver must be passed to the Page Object • Page elements are hidden in the Page Object • prevents inproper usage • maintainable • increases readability • puts focus on business case
  11. 11. Breaking the Limits <?php class LoginSection { private $webDriver; private $cssContext; public function __construct( SeleniumWebDriver $webDriver, string $cssContext ) { $this->webDriver = $webDriver; $this->cssContext = $cssContext; } public function fillCardnumberField(string $cardnumber) { ... } public function fillEmailField(string $email) { ... } public function fillPinField(string $pin ) { ... } public function toggleToEmail() { ... } public function toggleToCardnumber() { ... } public function clickLoginButton() { ... } ... • create separate representations of section, so-called Section Object • add section related methods to the Section Object • add section context
  12. 12. ... private function getCardnumberField(): array { return ['css' => $this->cssContext . ' input#cardnumber']; } private function getEmailField(): array { return ['css' => $this->cssContext . ' input#email']; } private function getPinField(): array { return ['css' => $this->cssContext . ' input#pin']; } private function getLoginButton(): array { return ['css' => $this->cssContext . ' input[type="submit"]']; } } Breaking the Limits • create separate representations of section, so-called Section Objects • add section related methods to the Section Object • add section context to • increase accuracy • induce generic reusability
  13. 13. <?php class LoginPage { private $webDriver; public function __construct(SeleniumWebDriver $webDriver) { $this->webDriver = $webDriver; } public function loadPage() { $this->webDriver->amOnPage($this->getUrl()); } private function getUrl(): string { return 'http://www.payback.mx'; } ... Breaking the Limits • create separate representations of section, so-called Section Objects • add section related methods to the Section Object • add section context to • increase accuracy • induce generic reusability • Page related methods remain in the Page Object
  14. 14. ... private $headerNavigation; private $loginSection; public function getHeaderNavigation(): HeaderNavigation { if ($this->headerNavigation === null) { $this->headerNavigation = new HeaderNavigation( $this->webDriver, 'body > nav#pb-navbar'); } return $this->headerNavigation; } public function getLoginSection(): LoginSection { if ($this->loginSection === null) { $this->loginSection = new LoginSection( $this->webDriver, 'body > div.pb-container_first'); } return $this->headerNavigation; } } Breaking the Limits • create separate representations of section, so-called Section Objects • add section related methods to the Section Object • add section context to • increase accuracy • induce generic reusability • Page related methods remain in the Page Object • Page Objects serve as Container for Section Objects
  15. 15. <?php class LoginCest { public function headerLoginTest(SeleniumWebDriver $I) { $loginPage = new LoginPage($I); $loginPage->loadPage(); $inlineLogin = $loginPage->getLoginSection(); $inlineLogin->fillCardnumberField('1111111111'); $inlineLogin->fillPinField('4321'); $headerNavigation = $loginPage->getHeaderNavigation(); $headerNavigation->expandLoginSection(); $headerLogin = $headerNavigation->getLoginSection(); $headerLogin->fillCardnumberField('5010961962'); $headerLogin->fillPinField('1234'); $headerLogin->clickLoginButton(); $I->see('Welcome'); } } Breaking the Limits • create separate representations of section, so-called Section Objects • add section related methods to the Section Object • add section context • increase accuracy • induce generic reusability • Page related methods remain in the Page Object • Page Objects serve as Container for Section Objects • targeted and parallel usage of the same section in one test case
  16. 16. Test Case Page Object Section Object Test Driver CSS Context 1 1 uses has uses * uses uses defines has *1 * * 1 1 1 * * 1 *
  17. 17. Breaking the Limits <?php class HeaderNavigation { private $webDriver; private $cssContext; private $loginSection; public function __construct( SeleniumWebDriver $webDriver, string $cssContext ) { $this->webDriver = $webDriver; $this->cssContext = $cssContext; } public function getLoginSection(): LoginSection { if ($this->loginSection === null) { $this->loginSection = new LoginSection( $this->webDriver, $this->cssContext . ' div.pb-nav-login-panel‘ ); } return $this->headerNavigation; } ... • … • Section Objects can be Containers for other Section Objects, too
  18. 18. Thank Y ou robert.bossek@qualityminds.de Robert Bossek
  19. 19. Questions? Robert Bossek robert.bossek@qualityminds.de

×