Pytest actual Web Testing Framework

https://www.jianshu.com/p/9a03984612c1?utm_campaign=hugo&utm_medium=reader_share&utm_content=note&utm_source=weixin-timeline&from=timeline&isappinstalled=0

Project structure

用例层(测试用例)
  |
Fixtures层(业务流程)
  |
PageObject层
  |
Utils实用方法层  

Use pytest-selenium

Basics

# test_baidu.py
def test_baidu(selenium): selenium.get('https://www.baidu.com') selenium.find_element_by_id('kw').send_keys('简书 韩志超') selenium.find_element_by_id('su').click() 

run

$ pytest test_baidu.py --driver=chrome

Or configurations of the pytest.ini

[pytest]
addopts = --driver=chrome

Use chrome options

# conftest.py
import pytest
@pytest.fixture
def chrome_options(chrome_options): # 覆盖原有chrome_options chrome_options.add_argument('--start-maximized') # chrome_options.add_argument('--headless') return chrome_options 

Page Object层

The basic model

# baidu_page.py
class BaiduPage(object): search_ipt_loc = ('id', 'kw') search_btn_loc = ('id', 'su') def __init__(self, driver): self.driver = driver def input_search_keyword(self, text): self.driver.find_element(*self.search_ipt_loc).send_keys(text) def click_search_button(self): self.driver.find_element(*self.search_btn_loc).click() def search(self, text): self.input_search_keyword(text) self.click_search_button() 

Call the method:

# test_baidu_page.py
from baidu_page import BaiduPage

def test_baidu_page(selenium): baidu = BaiduPage(selenium) baidu.search('简书 韩志超') 

Use the page base class

# pages/base_page.py
class BasePage(object): def __init__(self, driver): self.driver = driver def input(self, element_loc, text): element = self.driver.find_element(*element_loc) element.clear() element.send_keys(text) def click(self, element_loc): self.driver.find_element(*element_loc).click() 
# pages/baidu_page.py
from pages.base_page import BasePage

class BaiduPage(BasePage): search_ipt_loc = ('id', 'kw') search_btn_loc = ('id', 'su') def input_search_keyword(self, text): self.input(self.search_ipt_loc, text) def click_search_button(self): self.click(self.search_btn_loc) def search(self, text): self.input_search_keyword(text) self.click_search_button() 

Fixtures business layer

# conftest.py
import pytest
from pages.baidu_page import BaiduPage()

@pytest.fixture(scope='session') def baidu_page(selenium): return BaiduPage(selenium) 

EXAMPLE layer with

# test_baidu_page2.py
def test_baidu_page(baidu_page): baidu_page.search('简书 韩志超') assert '韩志超' in baidu.driver.title 

Progressive steps

Click Add Product menu> - - the interdependence of cases should not be used if the part has the same business process use cases, such as the need to open the login page -> Login> Add to enter the product page
is not recommended for use in the following manner, and make the order carried out.

def test_login():
   ...
  
def test_click_menu(): ... def test_add_goods(): ... 

Recommended common encapsulation step, each call may be used to implement step Fixture progressive method, the following example.

# conftest.py
import pytest
from pages.login_page import LoginPage
from pages.menu_page import MenuPage from pages.add_goods_page import AddGoodsPage @pytest.fixture(scope='session') def login_page(selenium): return LoginPage(selenium) @pytest.fixture(scope='session') def menu_page(selenium, login_page): """登录后返回菜单页面""" login_page.login('默认用户名', '默认密码') # 也可以从数据文件或环境变量中读取 return MenuPage(selenium) @pytest.fixture(scope='session') def add_goods_page(selenium, menu_page): """从MenuPage跳到添加商品页面""" menu_page.click_menu('商品管理', '添加新商品') return AddGoodsPage(selenium) 
# test_ecshop.py
def test_login(login_page): login_page.login('测试用户名', '测试密码') assert login_page.get_login_fail_msg() is None def test_add_goods(add_goods_page): add_goods_page.input_goods_name('dell电脑') add_goods_page.input_goods_category("电脑") add_goods_page.input_goods_price('3999') add_goods_page.submit() assert add_goods_page.check_success_tip() is True 

Using Log

The necessary output information in the project can help us show some intermediate results and rapid positioning of the test procedure, although Pytest framework can automatically capture print information and output screen or report, and more standardized use logging records and log output .
Compared print, logging module may record information graded.

Log level

Practical Method layer, a page object layer, Fixture business layer, with layer embodiment can be used directly to output log logging, use.

# test_logging.py
import logging

def test_logging(): logging.debug('调试信息') logging.info('步骤信息') logging.warning('警告信息,一般可以继续进行') logging.error('出错信息') try: assert 0 except Exception as ex: logging.exception(ex) # 多行异常追溯信息,Error级别 logging.critical("严重出错信息") 

Use pytest run there will be no log information because Pytest default display only WARNING above grade log in information in error.
To turn on the screen in real-time log, display and modify the log level.

Log等级: NOTSET < DEBUG < INFO < WARNING(=WARN) < ERROR < CRITICAL

# pytest.ini
[pytest]
log_cli=True
log_cli_level=INFO 

Run pytest test_logging.py, view the results:

--------------------------------------------- live log call ----------------------------------------------
INFO     root:test_logging.py:5 步骤信息
WARNING  root:test_logging.py:6 警告信息,一般可以继续进行
ERROR    root:test_logging.py:7 出错信息
ERROR    root:test_logging.py:11 assert 0
Traceback (most recent call last):
  File "/Users/apple/Desktop/demo/test_logging.py", line 9, in test_logging
    assert 0
AssertionError: assert 0
CRITICAL root:test_logging.py:12 严重出错信息

Since the log level is INFO level settings, so debug log is not output.

For the different layers Use log level, a method may be practical level logging debug output layer, assembling the file path, the file read data, sql executed, sql query result and the like.

In the output layer PageObject info level logging, perform an action such as a page, and the like.
Fixtures layer and output layer may use cases necessary info, warning, or error level information as needed.

Log Format

The default log format does not display the execution time, we can also customize log output format.

# pytest.ini
...
log_cli_format=%(asctime)s %(levelname)s %(message)s
log_cli_date_format=%Y-%m-%d %H:%M:%S
  • %(asctime)sRepresents the time, the default for Sat Jan 13 21:56:34 2018this format, we can use log_cli_date_format to specify the time format.
  • %(levelname)sThe level of representation of this Article logs
  • %(message)sConcrete output

Pytest test_logging.py run again, displayed in the following format:

--------------------------------------------- live log call ----------------------------------------------
2019-11-06 21:44:50 INFO 步骤信息
2019-11-06 21:44:50 WARNING 警告信息,一般可以继续进行
2019-11-06 21:44:50 ERROR 出错信息
2019-11-06 21:44:50 ERROR assert 0
Traceback (most recent call last):
  File "/Users/apple/Desktop/demo/test_logging.py", line 9, in test_logging
    assert 0
AssertionError: assert 0
2019-11-06 21:44:50 CRITICAL 严重出错信息

More Log Display Options

  • % (Levelno) s: printing log level values
  • % (Pathname) s: print path currently executing program, in fact, sys.argv [0]
  • % (Filename) s: Print the name of the currently executing program
  • % (FuncName) s: printing log current function
  • % (Lineno) d: the current line number of the printing log
  • % (Thread) d: Print thread ID
  • % (ThreadName) s: print thread name
  • % (Process) d: Print Process ID

Log output to a file

Add the following configuration in pytest.ini

...
log_file = logs/pytest.log
log_file_level = debug
log_file_format = %(asctime)s %(levelname)s %(message)s
log_file_date_format = %Y-%m-%d %H:%M:%S

log_file output file path, the file is input to the log level, format, date format to be separately provided.
Unfortunately, the log output to a file each time you run a cover, do not support the append mode.

Use Hooks

Hooks can be changed using the running processes Pytest, Hooks method generally written in conftest.py, a fixed name.
Pytest of Hooks method is divided into six levels:

  1. Method when the guide hook
  2. Initialization of the hook method
  3. The method of collecting hook when cases of use
  4. Hook method of test runs
  5. Hook method when generating reports
  6. Hook method when breakpoint debugging

Hooks method Pytest complete API, you can refer to: the API Reference hook -04- (Hooks)

Change setting

The following method demonstrates the dynamic test report generation name.

# conftest.py
import os
from datetime import datetime
def pytest_configure(config): """Pytest初始化时配置方法""" if config.getoption('htmlpath'): # 如果传了--html参数 now = datetime.now().strftime('%Y%m%d_%H%M%S') config.option.htmlpath = os.path.join(config.rootdir, 'reports', f'report_{now}.html') 

Whether the above example, the user --html pass what each run, the project reports will be in the directory, generate report_运行时间.htmla new reporting format.
Hook pytest_configure is a fixed method when Pytest guide, we again this method can be achieved when Pytest initial configuration, put our methods to be performed (methods become hook) or in a use case conftest.py file.
config parameters are fixed parameters of the method, the plug comprising at Pytest initialization, all of the command line parameters, INI project configuration.

You can use Python's introspection method Print (config., Dict ) to view the config object's properties.

Typically, by config.getoption - to get the value of the command line parameter item ( 'html'). Use config.getini ( 'log_file') can get the value of the configuration item pytest.ini file.

Add custom options and configurations

Suppose we want to send Email to achieve a complete run function.
We customize a command-line parameter entry --send-email, does not require a parameter value. When a user operation to bring the parameters, we send a report, not hair without running the following format:

pytest test_cases/ --html=report.html --send-email

Here, the general should cooperate to Mr. --html report.
Since Pytest itself does not --send-email this parameter, we need to be added by Hooks method.

# conftest.py
def pytest_addoption(parser): """Pytest初始化时添加选项的方法""" parser.addoption("--send-email", action="store_true", help="send email with test report") 

In addition, we also need to send an email message subject, body, recipients and other configuration information. We can put this information in the configuration to pytest.ini, such as:

# pytest.ini
...
email_subject = Test Report
email_receivers = superhin@126.com,[email protected]
email_body = Hi,all\n, Please check the attachment for the Test Report. 

It should be noted that the custom configuration options need to register in order to use, registration as follows.

# conftest.py
def pytest_addoption(parser): ... parser.addini('email_subject', help='test report email subject') parser.addini('email_receivers', help='test report email receivers') parser.addini('email_body', help='test report email body') 

Send Email function realization

Earlier we just add the Email configuration and operating parameters, we Hook method when generating a report, add transmission parameters according to the Email function, the following example.

from utils.notify import Email
# conftest.py
def pytest_terminal_summary(config): """Pytest生成报告时的命令行报告运行总结方法""" send_email = config.getoption("--send-email") email_receivers = config.getini('email_receivers').split(',') if send_email is True and email_receivers: report_path = config.getoption('htmlpath') email_subject = config.getini('email_subject') or 'TestReport' email_body = config.getini('email_body') or 'Hi' if email_receivers: Email().send(email_subject, email_receivers, email_body, report_path) 

Use allure-pytest

allure style is a very rich reporting framework.
Installation: pip install allure-pytest


 
allure Report

Reference documents: https://docs.qameta.io/allure/#_installing_a_commandline

Allure report contains the following pieces:

  • Overview: Overview
  • Categories: Failed use case classification
  • Suites: measuring gloves member, corresponding to the test class pytest
  • Graphs: graphs, reports by state with an overall embodiment, different severity levels and marked execution time distribution.
  • Timeline: Timeline of execution
  • Behaviors: BDD driving behavior patterns, by Epic, function, scenes user
    to mark and organizations use cases.
  • Pachages: according to the package directory to see the use case

Example labeled with

pytest-allure embodiment can automatically recognize the failure by pytest through, skip, xfail state and other reasons, and to provide more additional markers, the information to improve the use cases.

Further, allure provides many additional embodiments numerals or tissue with supplemental information with embodiments.

Mark test procedure

@allure.step('')

@allure.step
def func(): pass 

When this method is invoked with the embodiment, the report will be regarded as a step, according to the call nesting relationship recognition step.

To add extra information use case

Add attachments
  • @allure.attach.file('./data/totally_open_source_kitten.png', attachment_type=allure.attachment_type.PNG)
Add a title and description
  • @allure.description('')
  • @allure.description_html('')
  • @allure.title("This test has a custom title")
Add links, issue links, link the use case
  • @allure.link('http://...')
  • @ Allure.issue ( 'B140', 'Bug description')
  • @ Allure.testcase ( 'http: // ...', 'example name')

Example BDD mode tissues

  • @allure.epics('')
  • @allure.feature('')
  • @allure.story('')
  • @allure.step('')

You can run as story or feature

  • --allure-epics
  • --allure-features
  • --allure-stories

Severity mark

  • @allure.severity(allure.severity_level.TRIVIAL)
  • @allure.severity(allure.severity_level.NORMAL)
  • @allure.severity(allure.severity_level.CRITICAL)

Select the priority of execution in the following ways

--allure-severities normal,critical

Generate reports allure

pytest --alluredir=报告文件夹路径

After running the folder will have a xml format of the report file.
This report documents the use of plug-in to resolve directly jenkinz.
If you want to see local html format reports, you need to install allure.
installation method:

  • Mac: brew install allure
  • CentOS: yum install allure
  • Windows: Download , unzip outside download, go to the bin directory, you can use allure.bat. Use, generate html reports: 
allure generate 生成allure报告的文件夹

Windows can be used allure.bat generate in the bin directory allure of ...

Or by launching the report static service:

allure serve 生成allure报告的文件夹

It will automatically pop up a browser to access report generation.

Pytest actual testing framework APP

APP and belong to the same Web UI layer, we can use the same hierarchy contains Page Object pattern. The difference is that we need to customize driver this Fixture.

# conftest.py
import pytest
from appium import webdriver
@pytest.fixture(scope='session') def driver(): caps = { "platformName": "Android", "platformVersion": "5.1.1", "deviceName": "127.0.0.1:62001", "appPackage": "com.lqr.wechat", "appActivity": "com.lqr.wechat.ui.activity.SplashActivity", "unicodeKeyboard": True, "resetKeyboard": True, "autoLaunch": False } driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', caps) driver.implicitly_wait(10) yield driver driver.quit() 

Fixture and other driver or incorporated directly with the embodiments as a parameter can be used.

# test_weixin.py
def test_weixin_login(driver): driver.find_element_by_xpath('//*[@text="登录"]').click() ... 

Use pytest-variables

Installation by pip install pytest-variables
If we need to specify the device configuration and service Appium address used at runtime, we can put these configurations wrote a JSON file, then use pytest-variables plug load these variables.
caps.json contents of the file:

{
  "caps": {
    "platformName": "Android",
    "platformVersion": "5.1.1", "deviceName": "127.0.0.1:62001", "appPackage": "com.lqr.wechat", "appActivity": "com.lqr.wechat.ui.activity.SplashActivity", "unicodeKeyboard": true, "resetKeyboard": true, "autoLaunch": false }, "server": "http://localhost:4723/wd/hub" } 

Fixtures used:

# conftest.py
...
@pytest.fixture(scope='session')
def driver(variables): caps = variables['caps'] server = variables['server'] driver = webdriver.Remote(server, caps) ... 

Run method:

pytest test_weixin.py --variables caps.json

If you have multiple configurations can be caps.json format, save multiple profiles, load the specified configuration file to run. Operational parameters can also be added to the pytest.ini of addopts in.

Setup and cleanup

In order to ensure that each executing the use case does not affect each other, we can take each use case starts app are performed completely close the app, which belong to the use case method level Fixture method.
Meanwhile, since the execution time of the first embodiment is also called the app starts Fixture, where we need to set the default device is not connected to the automatic start app, i.e. caps configured autoLaunch = False.
Add the following Fixture method in conftest.py in:

# conftest.py
...
@pytest.fixture(scope='function', autouse=True)
def boot_close_app(driver): driver.boot_app() yield driver.close_app() 

Page objects and other service encapsulation layer may Fixture Web reference model framework.



Author: HAN super
link: https: //www.jianshu.com/p/9a03984612c1
Source: Jane book
Jane book copyright reserved by the authors, are reproduced in any form, please contact the author to obtain authorization and indicate the source.
 

Guess you like

Origin www.cnblogs.com/QaStudy/p/11828978.html