当前位置:网站首页>UI automation test: selenium+po mode +pytest+allure integration
UI automation test: selenium+po mode +pytest+allure integration
2022-07-03 21:02:00 【Little brother said test】
I am not involved in WebUI automated testing , But in order to improve their technology , There is no harm in learning more , No more nonsense , At present, the mainstream webUI The test framework should still be selenium, Considering maintainability 、 Expansibility 、 Reusability, etc , We use PO Pattern to write our script , This document also mainly integrates Selenium+PO Pattern +Pytest+Allure, Now let's get to the point . notes : At the end of the article Github Address
Technical premise :python、selenium、pytest Basic knowledge of
1. Project structure catalog :

2. PO Model is introduced
PO Model features :
- Easy to maintain
- High reusability
- The script is easy to read and understand
PO Model elements :
1. stay PO The pattern is abstractly encapsulated into a BasePage class , The base class should have one that only implements webdriver Properties of instances
2. Each one pag inherit BasePage, adopt driver To manage Ben page The element in the will page The operations in are encapsulated into methods one by one
3. TestCase rely on page class , So as to achieve the corresponding test steps

3. BasePage Page encapsulation
import logging
import os
import time
from datetime import datetime
from time import sleep
from selenium import webdriver
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from selenium.common.exceptions import TimeoutException, NoSuchElementException
from Utils.myLog import MyLog
"""
This class encapsulates all operations , All pages inherit this class
"""
class BasePage(object):
def __init__(self, driver):
self.logger = MyLog().getLog()
self.driver = driver
# Wait for the element to be visible
def wait_eleVisible(self, loc, timeout=30, poll_frequency=0.5, model=None):
"""
:param loc: Element location expression ; A tuple type , The way of expression ( Element location type , Element positioning method )
:param timeout: The upper limit of waiting
:param poll_frequency: Polling frequency
:param model: Wait for failure , Screenshot operation , The function annotation to be expressed in the picture file
:return:None
"""
self.logger.info(f' wait for "{model}" Elements , Positioning mode :{loc}')
try:
start = datetime.now()
WebDriverWait(self.driver, timeout, poll_frequency).until(EC.visibility_of_element_located(loc))
end = datetime.now()
self.logger.info(f' wait for "{model}" Duration :{end - start}')
except TimeoutException:
self.logger.exception(f' wait for "{model}" Element failed , Positioning mode :{loc}')
# Screenshot
self.save_webImgs(f" Waiting elements [{model}] Something unusual happened ")
raise
# Wait for the element to be invisible
def wait_eleNoVisible(self, loc, timeout=30, poll_frequency=0.5, model=None):
"""
:param loc: Element location expression ; A tuple type , The way of expression ( Element location type , Element positioning method )
:param timeout: The upper limit of waiting
:param poll_frequency: Polling frequency
:param model: Wait for failure , Screenshot operation , The function annotation to be expressed in the picture file
:return:None
"""
logging.info(f' wait for "{model}" disappear , Element localization :{loc}')
try:
start = datetime.now()
WebDriverWait(self.driver, timeout, poll_frequency).until_not(EC.visibility_of_element_located(loc))
end = datetime.now()
self.logger.info(f' wait for "{model}" Duration :{end - start}')
except TimeoutException:
self.logger.exception(f' wait for "{model}" Element failed , Positioning mode :{loc}')
# Screenshot
self.save_webImgs(f" Waiting elements [{model}] Disappear abnormally ")
raise
# Find an element element
def find_element(self, loc, model=None):
self.logger.info(f' lookup "{model}" Elements , Element localization :{loc}')
try:
return self.driver.find_element(*loc)
except NoSuchElementException:
self.logger.exception(f' lookup "{model}" Element failed , Positioning mode :{loc}')
# Screenshot
self.save_webImgs(f" Look for the element [{model}] abnormal ")
raise
# Look for the element elements
def find_elements(self, loc, model=None):
self.logger.info(f' lookup "{model}" Set of elements , Element localization :{loc}')
try:
return self.driver.find_elements(*loc)
except NoSuchElementException:
self.logger.exception(f' lookup "{model}" Element set failed , Positioning mode :{loc}')
# Screenshot
self.save_webImgs(f" Find element set [{model}] abnormal ")
raise
# Input operation
def input_text(self, loc, text, model=None):
# Look for the element
ele = self.find_element(loc, model)
# Input operation
self.logger.info(f' stay "{model}" Input "{text}", Element localization :{loc}')
try:
ele.send_keys(text)
except:
self.logger.exception(f'"{model}" Input operation failed !')
# Screenshot
self.save_webImgs(f"[{model}] Input exception ")
raise
# Clear operation
def clean_inputText(self, loc, model=None):
ele = self.find_element(loc, model)
# Clear operation
self.logger.info(f' eliminate "{model}", Element localization :{loc}')
try:
ele.clear()
except:
self.logger.exception(f'"{model}" Clear operation failed ')
# Screenshot
self.save_webImgs(f"[{model}] Clear exceptions ")
raise
# Click on the action
def click_element(self, loc, model=None):
# First find the element and click
ele = self.find_element(loc, model)
# Click on the action
self.logger.info(f' Click on "{model}", Element localization :{loc}')
try:
ele.click()
except:
self.logger.exception(f'"{model}" Click failed ')
# Screenshot
self.save_webImgs(f"[{model}] Click exception ")
raise
# Get text content
def get_text(self, loc, model=None):
# Find the element first and get the text content
ele = self.find_element(loc, model)
# Get text
self.logger.info(f' obtain "{model}" Element text content , Element localization :{loc}')
try:
text = ele.text
self.logger.info(f' obtain "{model}" The text content of the element is "{text}", Element localization :{loc}')
return text
except:
self.logger.exception(f' obtain "{model}" Element text content failed , Element localization :{loc}')
# Screenshot
self.save_webImgs(f" obtain [{model}] The text content is abnormal ")
raise
# Get attribute value
def get_element_attribute(self, loc, name, model=None):
# First find the element to get the attribute value
ele = self.find_element(loc, model)
# Get element attribute value
self.logger.info(f' obtain "{model}" Element attributes , Element localization :{loc}')
try:
ele_attribute = ele.get_attribute(name)
self.logger.info(f' obtain "{model}" Elements "{name}" The property set is "{ele_attribute}", Element localization :{loc}')
return ele_attribute
except:
self.logger.exception(f' obtain "{model}" Elements "{name}" Property failed , Element localization :{loc}')
# Screenshot
self.save_webImgs(f" obtain [{model}] Property exception ")
raise
# iframe Switch
def switch_iframe(self, frame_refer, timeout=30, poll_frequency=0.5, model=None):
# wait for iframe There is
self.logger.info('iframe Switching operation :')
try:
# Switch == index\name\id\WebElement
WebDriverWait(self.driver, timeout, poll_frequency).until(
EC.frame_to_be_available_and_switch_to_it(frame_refer))
sleep(0.5)
self.logger.info(' Switch successful ')
except:
self.logger.exception('iframe Switch failed !!!')
# Screenshot
self.save_webImgs(f"iframe Switching exception ")
raise
# Window switch = If you are switching to a new window ,new. If it is to return to the default window ,default
def switch_window(self, name, cur_handles=None, timeout=20, poll_frequency=0.5, model=None):
"""
Get... Before calling window_handles
:param name: new Represents the latest open window . default Represents the first window . Other values are expressed as the window's handles
:param cur_handles:
:param timeout: The upper limit of waiting
:param poll_frequency: Polling frequency
:param model: Wait for failure , Screenshot operation , The function annotation to be expressed in the picture file
:return:
"""
try:
if name == 'new':
if cur_handles is not None:
self.logger.info(' Switch to the latest open window ')
WebDriverWait(self.driver, timeout, poll_frequency).until(EC.new_window_is_opened(cur_handles))
window_handles = self.driver.window_handles
self.driver.swich_to.window(window_handles[-1])
else:
self.logger.exception(' Switch failed , There is no information to switch windows !!!')
self.save_webImgs(" Switch failed _ There is no information to switch windows ")
raise
elif name == 'default':
self.logger.info(' Switch to the default page ')
self.driver.switch_to.default()
else:
self.logger.info(' Switch to handles The window of ')
self.driver.swich_to.window(name)
except:
self.logger.exception(' Failed to switch windows !!!')
# Screenshot
self.save_webImgs(" Switch failed _ There is no information to switch windows ")
raise
# Screenshot
def save_webImgs(self, model=None):
# filepath = Refers to the image storage directory /model( Page function name )_ The current time is seconds .png
# Screenshot save Directory
# Splice log folder , If it doesn't exist, it will be created automatically
cur_path = os.path.dirname(os.path.realpath(__file__))
now_date = time.strftime('%Y-%m-%d', time.localtime(time.time()))
screenshot_path = os.path.join(os.path.dirname(cur_path), f'Screenshots\\{now_date}')
if not os.path.exists(screenshot_path):
os.mkdir(screenshot_path)
# current time
dateNow = time.strftime('%Y%m%d_%H%M%S', time.localtime(time.time()))
# route
filePath = '{}\\{}_{}.png'.format(screenshot_path, model, dateNow)
try:
self.driver.save_screenshot(filePath)
self.logger.info(f" Screen capture successful , The picture path is {filePath}")
except:
self.logger.exception(' Screen capture failed !')
# sign out
def get_driver(self):
return self.driver
4. Page inheritance BasPage
from Common.basePage import BasePage
from selenium.webdriver.common.by import By
from time import sleep
class BaiduIndex(BasePage):
"""
Page elements
"""
# Baidu home page link
baidu_index_url = "https://www.baidu.com"
# Search box
search_input = (By.ID, "kw")
# " use Baidu Search " Button box
search_button = (By.ID, "su")
# Query operation
def search_key(self, search_key):
self.logger.info("【=== Search operations ===】")
# Wait for the user name text box element to appear
self.wait_eleVisible(self.search_input, model=' Search box ')
# Input content
self.input_text(self.search_input, " Atri ", model=" Search box ")
# Clear the contents of the text box
self.clean_inputText(self.search_input, model=' Search box ')
# enter one user name
self.input_text(self.search_input, text=search_key, model=' Search box ')
# Wait for the search button to appear
self.wait_eleVisible(self.search_button, model='" use Baidu Search " Search button ')
# Click the search button
self.click_element(self.search_button, model='" use Baidu Search " Search button ')
# After searching, wait for the interface to load
self.driver.implicitly_wait(10)
sleep(3)
5. pytest+allure Write test cases
notes :Pytest Integrate Allure Please refer to :https://www.cnblogs.com/huny/p/13752406.html
import os
import time
import pytest
import allure
from time import sleep
from selenium import webdriver
from PageObject.baiduIndex import BaiduIndex
driver = webdriver.Chrome()
baidu_index = BaiduIndex(driver)
@pytest.fixture(scope="class")
def init():
# Open the browser , Visit the login page
baidu_index.logger.info("\nWebDriver Initializing ...")
driver.get(baidu_index.baidu_index_url)
baidu_index.logger.info(f" Open the link : {baidu_index.baidu_index_url}...")
# window maximizing
driver.maximize_window()
# An implicit wait
driver.implicitly_wait(10)
baidu_index.logger.info("WebDriver Initialization complete !")
yield
driver.quit()
baidu_index.logger.info("WebDriver Quit successfully ...")
@allure.feature(" Baidu search ")
class TestBaiduSearch:
@allure.story(" Search for specified keywords ")
@pytest.mark.baidu_search
@pytest.mark.parametrize("key_word", [
" ha-ha ",
" ha-ha ",
], )
def test_search(self, init, key_word):
# @pytest.mark.parametrize A parameterized
baidu_index.search_key(key_word)
web_title = driver.title
assert " ha-ha _ Baidu search " == web_title
6. Generate Allure Test report

Github Address :https://github.com/Zimo6/Selenium_Demo
The following is the supporting information , For doing 【 software test 】 For our friends, it should be the most comprehensive and complete war preparation warehouse , This warehouse also accompanied me through the most difficult journey , I hope it can help you !
Last : It can be in the official account : Programmer Xiaohao ! Get a free copy of 216 Page software testing engineer interview guide document information . And the corresponding video learning tutorial is free to share !, It includes basic knowledge 、Linux necessary 、Shell、 The principles of the Internet 、Mysql database 、 Special topic of bag capturing tools 、 Interface testing tool 、 Test advanced -Python Programming 、Web automated testing 、APP automated testing 、 Interface automation testing 、 Testing advanced continuous integration 、 Test architecture development test framework 、 Performance testing 、 Safety test, etc. .
If my blog helps you 、 If you like my blog content , please “ give the thumbs-up ” “ Comment on ” “ Collection ” One button, three links ! Friends who like software testing , You can join our testing technology exchange group :779450660 There are various software testing resources and technical discussions )
边栏推荐
- Mysql database ----- common commands of database (based on database)
- Last week's content review
- Compilation Principle -- syntax analysis
- Rhcsa third day notes
- 阻塞非阻塞和同步异步的区分 参考一些书籍
- Preliminary practice of niuke.com (11)
- 淺析 Ref-NeRF
- 11-grom-v2-05-initialization
- 【c】 Digital bomb
- 2022 safety officer-c certificate examination and safety officer-c certificate registration examination
猜你喜欢
![[Yugong series] go teaching course 002 go language environment installation in July 2022](/img/47/35b4fb0354122e233977b261ef405b.png)
[Yugong series] go teaching course 002 go language environment installation in July 2022

Discussion Net legacy application transformation

2022 high voltage electrician examination and high voltage electrician reexamination examination

Link aggregation based on team mechanism

@Scenario of transactional annotation invalidation

thrift go

Node MySQL serialize cannot rollback transactions

Research Report on the overall scale, major manufacturers, major regions, products and application segmentation of rotary tablet presses in the global market in 2022

19、 MySQL -- SQL statements and queries

String and+
随机推荐
11-grom-v2-05-initialization
How to handle wechat circle of friends marketing activities and share production and release skills
Wireless network (preprocessing + concurrent search)
上周内容回顾
Hcie security Day10: six experiments to understand VRRP and reliability
Get log4net log file in C - get log4net log file in C
Kernel symbol table
Redis data migration (II)
LabVIEW training
强化学习-学习笔记1 | 基础概念
Memory analyzer (MAT)
Inventory 2021 | yunyuansheng embracing the road
@Scenario of transactional annotation invalidation
Qualcomm platform WiFi update disconnect end open event
Xai+ network security? Brandon University and others' latest "interpretable artificial intelligence in network security applications" overview, 33 page PDF describes its current situation, challenges,
同花顺开户注册安全靠谱吗?有没有风险的?
Sort out several network request methods of JS -- get rid of callback hell
MySQL——规范数据库设计
Measurement fitting based on Halcon learning -- Practice [1]
18、 MySQL -- index