Selenium pytest 基础讲解

郑郑 · 2019年09月18日 · 最后由 心意已决 回复于 2020年11月25日 · 6946 次阅读

相信用 python 做自动化的人,对于 pytest 这个框架一定不陌生,自动化必备神器,比起 unittest 的笨重,pytest 可以说是非常好用的一个框架了。从最开始的 unittest 用户转变为 pytest 后就再也不想用 unittest 了,下面简单讲解下 pytest 的一些基本结构及应用。
pytest 集成了很多现成可用的库,可以 pip 安装后直接用。像 pytest-metadata 就是,下面会讲解到。pytest 提供了 setup.cfg 文件,很多初始的配置都可以写在里面,例如用什么浏览器,浏览器 driver 的地址,生成什么类型的 report,运行的 case 目录地址等等。上面说到的 pytest-metadata 也可以配置在里面,设置变量参数用到,如设置用户名、密码、url 等等,如下图所示。

设置完配置参数后,运行时就会比较简单,下一步当然是把一些公用的步骤提取出来,比如登陆,这样不用每个脚本都写一遍登陆了。pytest 有什么办法实现呢?当然有,pytest 提供了一个叫 conftest.py 的文件来实现,在这个 py 文件中写一个函数,加上@pytest.fixture装饰器,那么其他 case 运行时,都会先执行这个脚本,把这个函数当作参数自动入参到 case 中,相当于就可以接着 conftest 中的步骤进行下一步操作了,用来存放一些公用的步骤再适合不过了,如果跑完 case 想进行清理工作的话,就可以用 yield,把处理工作写到 yield 后面即可

这些处理完下一步当然就是编写 case 了,上面有用到 metadata 这个库,那具体怎么使用呢?很简单,直接上图

给函数入参 metadata,然后 metadata 后带 setup.cfg 中定义的变量名就行,是不是很方便呢!
那怎么批量运行 case 呢?pytest 也帮你解决了,他会默认去寻找文件名、类名、函数名是 test 或者 Test 开头的文件去批量执行。执行完之后怎么生成报告呢?可以 pip install pytest-html 后,如上图般在 setup.cfg 里配置好,那么执行完所有脚本后就会自动生成 html 报告,也算比较详细的一份报告了。当然也可以和 allure 相结合,这个之后有空写篇文章讲解下。
还有跳过某些用例不执行、一次运行多个脚本、失败后重复运行、为脚本设置标签等等之后文章有空再讲解。
鉴于大家都想要一份 demo 代码,我在下方粘贴出,大家可以参考:
目录结构为:

setup.cfg 内容为:
[tool:pytest]
addopts = --metadata url "https://github.com/"
--metadata username "此处输入 github 用户名"
--metadata password "此处输入 github 密码"
--html report/report.html
--alluredir report
--reruns 1
-n 2
--driver Chrome

testpaths = tests

requirements 文件内容为:
pytest-bdd==3.0.0
pytest==3.9.2
pytest-rerunfailures==6.0
pytest-xdist==1.26.1

conftest 的代码为

-- coding:utf-8 --

import pytest
from tests.commons import elements
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

@pytest.fixture
def selenium(selenium, metadata):
selenium.get(metadata['url'])
return selenium

commons 下的 elements 文件代码为:

-- coding:utf-8 --

from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

send_keys 输入方法封装

class TestFindElement(object):

def find_css_send(self, selenium, css, number):
try:
WebDriverWait(selenium, 10, 0.5).until(
EC.visibility_of_element_located((By.CSS_SELECTOR, css)))
selenium.find_element_by_css_selector(css).send_keys(number)
except:
print("%s 元素不可见" % css)

def find_id_send(self, selenium, id, number):
try:
WebDriverWait(self, selenium, 10, 0.5).until(
EC.visibility_of_element_located((By.ID, id)))
selenium.find_element_by_id(id).send_keys(number)
except:
print("%s 元素不可见" % id)

def find_name_send(self, selenium, name, number):
try:
WebDriverWait(selenium, 10, 0.5).until(
EC.visibility_of_element_located((By.NAME, name)))
selenium.find_element_by_name(name).send_keys(number)
except:
print("%s 元素不可见" % name)

def find_xpath_send(self, selenium, xpath, number):
try:
WebDriverWait(selenium, 10, 0.5).until(
EC.visibility_of_element_located((By.XPATH, xpath)))
selenium.find_element_by_xpath(xpath).send_keys(number)
except:
print("%s 元素不可见" % xpath)

# click 点击方法封装
def find_css_click(self, selenium, css):
try:
WebDriverWait(selenium, 10, 0.5).until(
EC.visibility_of_element_located((By.CSS_SELECTOR, css)))
selenium.find_element_by_css_selector(css).click()
except:
print("%s 元素不可见" % css)

def find_id_click(self, selenium, id):
try:
WebDriverWait(selenium, 10, 0.5).until(
EC.visibility_of_element_located((By.ID, id)))
selenium.find_element_by_id(id).click()
except:
print("%s 元素不可见" % id)

def find_name_click(self, selenium, name):
try:
WebDriverWait(selenium, 10, 0.5).until(
EC.visibility_of_element_located((By.NAME, name)))
selenium.find_element_by_name(name).click()
except:
print("%s 元素不可见" % name)

def find_xpath_click(self, selenium, xpath):
try:
WebDriverWait(selenium, 10, 0.5).until(
EC.visibility_of_element_located((By.XPATH, xpath)))
selenium.find_element_by_xpath(xpath).click()
except:
print("%s 元素不可见" % xpath)

def find_xpath(self, selenium, xpath):
return selenium.find_element_by_xpath(xpath)

page 下 login 的代码为

-- coding:utf-8 --

from tests.commons.elements import TestFindElement

class LoginPage(TestFindElement):
username_element = '//[@id="login_field"]'
password_element = '//
[@id="password"]'
button_element = '//input[@name="commit"]'
img_element = '//*[@id="user-links"]/li[3]/details/summary/img'

def send_username(self, selenium, number):
return self.find_xpath_send(selenium, self.username_element,
number)

def send_password(self, selenium, number):
return self.find_xpath_send(selenium, self.password_element,
number)

def click_button(self, selenium):
return self.find_xpath_click(selenium,
self.button_element)

def click_img(self, selenium):
return self.find_xpath_click(selenium,
self.img_element)

tests 下 test_login 的代码为

-- coding:utf-8 --

from tests.page.login_page import LoginPage
from tests.commons import elements
import allure

@allure.feature('登陆功能')
class TestLogin(object):
@allure.story('登陆')
def test_login(self, selenium, metadata):
login_page = LoginPage()
result = 'zhengxingqu'
with allure.step("点击 login 链接"):
pass
login_page.find_xpath_click(selenium, "//a[@href='/login']")
with allure.step("输入用户名"):
pass
login_page.send_username(selenium, metadata['username'])
with allure.step("输入密码"):
pass
login_page.send_password(selenium, metadata['password'])
with allure.step("点击登陆按钮"):
pass
login_page.click_button(selenium)
with allure.step("点击头像"):
pass
login_page.click_img(selenium)
with allure.step("获取用户名"):
pass
name_text = login_page.find_xpath(selenium,
'//*[@id="user-links"]/li[3]/details/details-menu/div[1]/a/strong').text
assert name_text == result

完整的目录结构为

该项目为 demo 项目,故目录结构都比较简单随意,仅供学习 pytest 使用

共收到 11 条回复 时间 点赞

排版不太好😹
最好能提供一份 demo 代码

test_demo.py:None (test_demo.py)
test_demo.py:4: in
@allure.MASTER_HELPER.feature("测试 Dome")
E AttributeError: module 'allure' has no attribute 'MASTER_HELPER'

对酒当歌 回复

是的,哈哈,排版比较随意的,其实有一份 demo 代码,就是涉及到 github 的账号密码,我晚上可以改一下发出来

你是装的 pytest-allure-adaptor 还是 allure-pytest

对酒当歌 回复

demo 代码已提供在文章中,有需要的可以参考

郑郑 回复

暂时放弃了

郑郑 回复

装哪个好?

郑郑 回复

你是装的 pytest-allure-adaptor 还是 allure-pytest 这 2 个装哪个好?

solomon 回复

我是装的 allure-pytest,如果装 pytest-allure-adaptor 的话,有可能会碰到楼上相同的报错问题。

郑郑 回复

谢谢,正好试出来了。确实装 pytest-allure-adaptor 也出问题了。 :)

仅楼主可见
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册