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

From MozillaWiki
< B2G‎ | QA‎ | Automation‎ | Style Guide
Jump to: navigation, 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.
# Good
def test_that_advanced_search_does_not_find_item(self):

# Bad
def test_advanced_search(self):

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.
# Good
def method(self, parameter) 

# Bad
def method(self,parameter)
  • Lines should try not to have more than 100 characters.
  • Docstrings should conform to PEP0257 and should be on a single line wherever possible.
# Good
def click_login():
"""Clicks the login link."""

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

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

# Good
def login():
"""Logs in.

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

"""

# Bad
def login():
"""Logs in.
Clicks the login link and then waits for the home page to load."""
  • 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.
# Good
class TestThisSite:
    
# Bad
class test_this_site:

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.
@property
def search_term(self):
    return self.marionette.find_element(*self._search_box_locator).value
  • 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.
# Good
_my_locator = "css=#content > p > a"
    
# Bad
_my_locator = "css=#content>p>a"
  • Use Python tuples to define locators:
# Good
_my_locator = (By.ID, "content")

Actions

  • Methods that perform actions on the page should indicate the action in the method name.
# Good
def click_report_with_length(length)

# Bad
def report_length(length)
  • 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.
# Good
messages.send_an_sms_to_yourself()

# Bad
messages.open_sms_app()
messages.create_new_sms(receiver)
messages.type_content(content)
messages.send()

Variable Naming

  • Name your variables with units.
# Good 
timeout_in_seconds, width_in_pixels

# Bad
timeout, width
  • Don't shorten variable names.
# Good
self.time_out_error_time = 1000

# Bad
self.t_out_err_tim = 1000

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.

        
        # 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()

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)