当前位置:网站首页>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 )
边栏推荐
- 全网都在疯传的《老板管理手册》(转)
- Qualcomm platform WiFi update disconnect end open event
- [gd32l233c-start] 5. FLASH read / write - use internal flash to store data
- Qt6 QML Book/Qt Quick 3D/基础知识
- 11-grom-v2-04-advanced query
- How to modify the network IP addresses of mobile phones and computers?
- Reinforcement learning - learning notes 1 | basic concepts
- Borui data and Sina Finance released the 2021 credit card industry development report
- Kernel symbol table
- Mysql database ----- common commands of database (based on database)
猜你喜欢

Leetcode daily question 540 A single element in an ordered array Valentine's Day special article looking for a single dog in a pile of lovers ~ the clown is myself

Xai+ network security? Brandon University and others' latest "interpretable artificial intelligence in network security applications" overview, 33 page PDF describes its current situation, challenges,

Baohong industry | good habits that Internet finance needs to develop

Haven't expressed the artifact yet? Valentine's Day is coming. Please send her a special gift~

@Transactional注解失效的场景

Memory analyzer (MAT)
![[Tang Laoshi] C -- encapsulation: member variables and access modifiers](/img/be/0b38c0f1a27f819f7c79bcf634fbd4.jpg)
[Tang Laoshi] C -- encapsulation: member variables and access modifiers

Hcie security Day10: six experiments to understand VRRP and reliability

"Designer universe" APEC safety and health +: environmental protection Panda "xiaobaobao" Happy Valentine's Day 2022 | ChinaBrand | Asia Pacific Economic media

Single page application architecture
随机推荐
Gee calculated area
Baohong industry | good habits that Internet finance needs to develop
Thread, thread stack, method stack, the difference of creating thread
Interval product of zhinai sauce (prefix product + inverse element)
强化學習-學習筆記1 | 基礎概念
[Yugong series] February 2022 Net architecture class 004 ABP vNext used in WPF project
Get log4net log file in C - get log4net log file in C
Qualcomm platform WiFi update disconnect end open event
TLS environment construction and plaintext analysis
Rhcsa third day operation
2022 safety officer-c certificate examination and safety officer-c certificate registration examination
淺析 Ref-NeRF
Example of peanut shell inner net penetration
It is discussed that the success of Vit lies not in attention. Shiftvit uses the precision of swing transformer to outperform the speed of RESNET
Transformation between yaml, Jason and Dict
Producer consumer mode (multithreading, use of shared resources)
From the behind the scenes arena of the ice and snow event, see how digital builders can ensure large-scale events
Mysql database ----- common commands of database (based on database)
University of Electronic Science and technology | playback of clustering experience effectively used in reinforcement learning
Sightseeing - statistics of the number of shortest paths + state transfer + secondary small paths