B2G/QA/Automation/Style Guide/Python Script Style

From New wiki
Jump to navigation Jump to search

Python Script Style Guide

Naming

  • Module names should be called test_ and then behavioral areas.
   test_search.py
  • Test method names should always show the intent of the test case.

<source lang="python">

  1. Good

def test_that_advanced_search_does_not_find_item(self):

  1. Bad

def test_advanced_search(self): </source>

File Headers

  • Each file should have a completed copy of the MPL2 license block, immediately followed by an empty line.
  • Each file should pass PEP8 except for line length, see below.

<source lang="python">

  1. Good

def method(self, parameter)

  1. Bad

def method(self,parameter) </source>

  • Lines should try not to have more than 100 characters.
  • Docstrings should conform to PEP0257 and should be on a single line wherever possible.

<source lang="python">

  1. Good

def click_login(): """Clicks the login link."""

  1. Bad

def click_login(): """ Clicks the login link. """ </source>

Where not possible, the first line should be a summary.

<source lang="python">

  1. Good

def login(): """Logs in.

Clicks the login link and then waits for the home page to load.

"""

  1. Bad

def login(): """Logs in. Clicks the login link and then waits for the home page to load.""" </source>

  • Indenting should be a soft tab (4 spaces) as common with in Python. Do not mix tabs and spaces!
  • There should be no whitespace at the end of the file (as per PEP8).
  • Comments should be on the line above. Remember to update comments when changing code so that code matches the comments.
  • Comments should be used carefully. Try not to put comments that don't provide any additional value
  • Class names should be in Pascal style as this is Python idiomatic.

<source lang="python">

  1. Good

class TestThisSite:

  1. Bad

class test_this_site: </source>

Locators

  • Locator variables should be prefixed with _ to show that it is private.
  • Variables should be descriptive of the area and not clash with any properties.
  • Should have a suffix of _locator.
  • Accessing locators should be done through a property or method as this keeps the locator as read-only.

<source lang="python"> @property def search_term(self):

   return self.marionette.find_element(*self._search_box_locator).value

</source>

  • We should use locators in the following order of preference (there will be exceptions):
    • ID
    • Name
    • Class name
    • CSS selector
    • XPath
  • CSS locators should use whitespace for readability when using direct descendants.

<source lang="python">

  1. Good

_my_locator = "css=#content > p > a"

  1. Bad

_my_locator = "css=#content>p>a" </source>

  • Use Python tuples to define locators:

<source lang="python">

  1. Good

_my_locator = (By.ID, "content") </source>

Actions

  • Methods that perform actions on the page should indicate the action in the method name.

<source lang="python">

  1. Good

def click_report_with_length(length)

  1. Bad

def report_length(length) </source>

  • Actions should wait for the appropriate action to complete. This could be an implicit or explicit wait. For example, clicking a login button might explicitly wait for a username field to be visible.

Using High-Level Methods

  • A test script should remain a short entry point which leads to more details (like the main() function of a program). Don't detail every single tap and wait, in the test. Use methods that reflect a user's intent rather than a sequence of small steps the user has to do. The details of how to fulfill that intent will be in the page classes.

<source lang="python">

  1. Good

messages.send_an_sms_to_yourself()

  1. Bad

messages.open_sms_app() messages.create_new_sms(receiver) messages.type_content(content) messages.send() </source>

Variable Naming

  • Name your variables with units.

<source lang="python">

  1. Good

timeout_in_seconds, width_in_pixels

  1. Bad

timeout, width </source>

  • Don't shorten variable names.

<source lang="python">

  1. Good

self.time_out_error_time = 1000

  1. Bad

self.t_out_err_tim = 1000 </source>

Making Tests Locale Independent

It is recommended to make the test scripts (and especially the helper methods) locale independent, because this enables us to test devices in RTL locale. There are still some sections in gaiatest where it checks for the displayed English text, but unless one cannot avoid it, data-l10n-id attribute should be checked in place of any raw text comparison.

<source lang="python">

       # below method will not work in a non-English locale, 
       # should only be used when there is no appropriate tag for the Open App button
       button = self.root_element.find_element(*self._install_button_locator)
       Wait(self.marionette).until(lambda m: button.text == 'Open app')
       button.tap()
       # below code will tap 'Send Mozilla Feedback' button in any locale
       _send_feedback_locator = (By.CSS_SELECTOR, '[data-l10n-id="sendMozillaFeedback"]')
       element = Wait(self.marionette).until(
           expected.element_present(*self._send_feedback_locator))
       Wait(self.marionette).until(expected.element_displayed(element))
       element.tap()

</source>

The rules of thumb are:

  • We can check for the raw text in order to verify the user input (i.e., a phone number entered in the dialer app)
  • We check the data-l10n-id for any string that comes from Gaia only (i.e., an error message)