Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Writing automated tests - Best Practices with P...

Writing automated tests - Best Practices with Python, Selenium, Behave and Page Objects

Steps by Step to create a good automation project.

1 . Write Good Scenarios with Gherkin
2. Define your code language and BDD framework
3. Install selenium
4. Read and understand Page Objects
5. Organize your project
6. Create your pages
7. Create steps
8. Run

Avatar for Letícia Rostirola

Letícia Rostirola

December 08, 2018
Tweet

More Decks by Letícia Rostirola

Other Decks in Programming

Transcript

  1. Before Automating: BDD • Encouraging conversation between all involved •

    Writing down examples to make things clearer • Reduce ambiguity “Automating the scenarios resulting from the conversations is an optional next step.” Julien Biezemans Creator of Cucumber.js
  2. Gherkin: a natural language style “Gherkin is designed to be

    easy to learn by non-programmers, yet structured enough to allow concise description of examples to illustrate business rules in most real-world domains”.
  3. Why Test Automation? • Saves you time, money and people

    • Consistency of tests • Continuous Integration • Avoid boredom
  4. Cucumber Cucumber can be used to implement automated tests based

    on scenarios described in your Gherkin feature files. In the example given in step definitions: When she eats 3 cucumbers Cucumber extracts the text 3 from the step, converts it to an int and passes it as an argument to the method.
  5. Cucumber vs Behave vs Godog Cucumber: Java, JS, Ruby. Behave:

    Cucumber Python style. Godog: Cucumber for golang.
  6. Page Objects design pattern “Despite the term "page" object, these

    objects shouldn't usually be built for each page, but rather for the significant elements on a page. So a page showing multiple albums would have an album list page object containing several album page objects. There would probably also be a header page object and a footer page object.” Martin Fowler Software Developer
  7. Page Objects: Benefits • Create reusable code that can be

    shared across multiple test cases • Reduce the amount of duplicated code • If the user interface changes, the fix needs changes in only one place
  8. Page Objects: Example from lib.pages.basepage import BasePage from selenium.webdriver.common.by import

    By class LoginPage(BasePage): def __init__(self, context): BasePage.__init__(self, context.browser, base_url='http://twitter.com/') locator_dictionary = { "email" : (By.NAME, 'session[username_or_email]'), "password" : (By.NAME, 'session[password]'), "submit" : (By.CSS_SELECTOR, 'input[type="submit"]'), "error_message" : 'The email and password you entered did not match our records. Please double-check and try again.' } def signin(self, email, password): username_field = self.driver.find(self .locator_dictionary['email']) password_field = self.driver.find(self.locator_dictionary['password']) username_field.send_keys(email) password_field.send_keys(password) submit_button = self.driver.find(self.locator_dictionary['submit']) submit_button.click()
  9. Page Objects: BasePage class BasePage(object): def __init__(self, browser, base_url =

    'http://twitter.com/'): self.driver = browser self.base_url = base_url def find(self, selector): return self.driver.find_element(selector[0], selector[1]) def contains_content(self, text, timeout): try: elem = WebDriverWait(self.driver, timeout).until( EC.text_to_be_present_in_element((By.TAG_NAME, 'body'), text)) return elem except TimeoutException as ex: return False
  10. Tree https://github.com/ladylovelace/automation-behave-pageobjects . ├── features │ ├── config.py │ ├──

    config.py.dist │ ├── environment.py │ ├── lib │ │ ├── chromedriver │ │ └── pages │ │ ├── basepage.py │ │ ├── homepage.py │ │ └── loginpage.py │ ├── login_twitter.feature │ ├── steps │ │ ├── home.py │ │ └── login.py │ └── tweet.feature ├── README.md ├── requirements.txt ├── screenshot
  11. Features Feature: Tweet Allow valid users Post 280 characters limit

    per tweet To have a better day @rainy Scenario: Tweet like a crazy teenager > 280 chars Given the valid user is logged in on the homepage When user post invalid tweet Then the tweet button should be disabled @sunny @sanity Scenario: Tweet properly <= 280 chars Given the valid user is logged in on the homepage When user post valid tweet Then the tweet button should be enabled And the user should be able to tweet
  12. environment.py import os from selenium import webdriver from lib.pages.basepage import

    BasePage from lib.pages.loginpage import LoginPage def before_all(context): driver = webdriver.Chrome() driver.maximize_window() driver.implicitly_wait(10) context.browser = BasePage(driver) context.signin = LoginPage(context) def after_scenario(context, scenario): context.browser.screenshot(str(scenario))
  13. steps/page.py from behave import given, when, then from config import

    USER from features.lib.pages.loginpage import LoginPage @when(u'the "{user_type}" user logs in') def login(context, user_type): context.signin.signin(USER[user_type]['email'], USER[user_type]['pass']) @then(u'a login error message should display') def step_impl(context): message = context.browser.contains_content( LoginPage.locator_dictionary['error_message'], 5) assert message @rainy Scenario: Invalid login Given "invalid" user navigates to page “landing” When the "invalid" user logs in Then a login error message should display feature/steps/login.py feature/steps/login.py
  14. config.py (optional) USER = { 'valid': { 'email': 'YOUR_EMAIL', 'pass':

    'YOUR_PASS', 'username': 'YOUR_USERNAME', }, 'invalid': { 'email': '[email protected]', 'pass': 'mudar123', }, }
  15. Tips • Be aware of Chromedriver/chrome version ◦ Chrome headless

    requires chromedriver 2.3+ • Use Selenium explicit/implicit wait instead of python time.sleep function ◦ Better, faster and stronger • Use find_by_id (or similar) instead of find_by_xpath ◦ IE provides no native XPath-over-HTML solution
  16. Best Practices • "Tag" parts of your feature file •

    Gherkin common mistakes ◦ Using absolute values instead of configurable values ◦ Describing every action instead of a functionality ◦ Writing scripts in first person instead of third person • Good relationship with Frontenders > You will need IDs • The scenarios should run independently, without any dependencies on other scenarios