QA/Execution/Web Testing/Docs/Automation/StyleGuide: Difference between revisions
(added page region) |
|||
| Line 94: | Line 94: | ||
def report_length(length) | def report_length(length) | ||
</pre> | </pre> | ||
== Advanced: Page Regions == | |||
In some circumstances, for example where a header/navigation is common across the website, we will use a page region. The page region is a child class of the base Page Object, which is inherited by all page objects. This means that the navigation can be reached from any page object and herein lies the DRY! | |||
A brief example: | |||
<pre class="brush:py;toolbar:false;"> | |||
class BasePage(Page): | |||
@property | |||
def header(self): | |||
return BasePage.HeaderRegion(self.testsetup) | |||
class HeaderRegion(Page): | |||
_login_link = (By.ID, "home") | |||
@def click_login(self): | |||
self.selenium.find_element(*self._login_link).click() | |||
</pre> | |||
Referring to this page region with a property makes it very readable and concise from within the test. Clicking home during a test would be performed like this: | |||
<pre class="brush:py;toolbar:false;"> | |||
page_obj.header.click_login() | |||
</pre> | |||
Another example where this might be used is on a search results page, the page region being the search results element. | |||
= Tests = | = Tests = | ||
Revision as of 13:10, 3 October 2011
The goal of the style guide is to try provide rules to write code that looks the same no matter what project. It is a guide and is always up for discussion by the team. I have created templates based on the details below.
All Files
File Headers
- At the top of each file should have python file header
#!/usr/bin/env python
- Each file should have a completed copy of the MPL
- Each file should pass PEP8 except for line length, see below.
- I.e. parameters should have a comma and a space e.g.
# Good
def method(self, parameter)
# Bad
def method(self,parameter)
- Lines should try not to have more than 100 characters.
- 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.
- Class names should be in Pascal style as this is Python idiomatic.
# Good
class TestThisSite:
# Bad
class test_this_site:
Page Objects
General
- All Page Objects should inherit from Page in page.py.
- Page Objects should not do asserts. This should be done within the test.
- Each Page should be grouped within one module.
- If using mutliple words to describe a module separate them with underscores '_'
test_search.py
- Timeout time should be taken from pytest-mozwebqa via page.py's timeout property.
- Double quotes (") should be used instead of single (') throughout.
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.
- Suffix of _locator.
- Accessing Locators should be done through a property method as this keeps the locator as readonly.
@property
def search_box(self):
return self.search_box_locator
- This approach can also be used with get_* calls with Selenium making it more idiomatic for the call.
@property
def page_title(self):
return self.selenium.get_title()
- We should use locators in the following order of preference (there will be exceptions):
- ID
- Name
- CSS
- XPath
- Locators should include the strategy instead of using implied strategies.
# Good
_my_locator = "id=content"
# Bad
_my_locator = "content"
- 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"
- With Webdriver, use a Python tuple:
# 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)
Advanced: Page Regions
In some circumstances, for example where a header/navigation is common across the website, we will use a page region. The page region is a child class of the base Page Object, which is inherited by all page objects. This means that the navigation can be reached from any page object and herein lies the DRY!
A brief example:
class BasePage(Page):
@property
def header(self):
return BasePage.HeaderRegion(self.testsetup)
class HeaderRegion(Page):
_login_link = (By.ID, "home")
@def click_login(self):
self.selenium.find_element(*self._login_link).click()
Referring to this page region with a property makes it very readable and concise from within the test. Clicking home during a test would be performed like this:
page_obj.header.click_login()
Another example where this might be used is on a search results page, the page region being the search results element.
Tests
- Module names should be called test_ and then behavioral areas.
test_search_positive.py
- Test method signature should include mozwebqa to use pytest-mozwebqa plugin.
def test_example(self, mozwebqa):
- Test method names should always show the intent of the test case.
# Good
def test_that_advanced_search_does_not_find_item(self, mozwebqa):
# Bad
def test_advanced_search(self, mozwebqa):
- Tests should handle the asserts -- not the page objects.
Size of patches
To make sure that we can review your patch as quickly and efficiently as possibly we would like patches to have 1 test in them and the necessary changes to the Page Objects. This also limits the chances of merge conflicts later.