前段时间记录了一下pytest接口自动化测试,今天来记录pytest+allureUI自动化了 ,还是直接上代码吧。
目录
case#存放测试用例
common#存放测试公共方法
data#存放测试数据、定位元素
logs#存放日志文件
pages#存放页面页面元素,操作步骤
report#存放测试报告
getpathinfo.py#读取当前目录
pytest#pytest配置文件
requirements.txt#依赖包
学习框架
pytest单元测试框架+allure生成测试报告
结构设计
1.每一个页面的所有用例组合在一个测试类里面生成一个py文件
2.将每个页面用例的操作步骤封装在一个测试类里面生成一个py文件
3.将测试数据,定位元素存放在yml文件中
4.通过allure生成测试报告
学习内容
1.pytes单元测试框架
2.allure生成测试报告
3.yml文件存放测试数据通过parametrize进行参数化
4.无界面运行测试用例
练习代码
getpathinfo.py #获取当前路径
import os
def get_path():
curpath = os.path.dirname(os.path.realpath(__file__))
return curpath
if __name__ == '__main__':
print("测试路径",get_path())
getpathinfo.py
pytest.ini #存放pytest配置文件
#pytest.ini
[pytest]
#addopts = -v --reruns 1 --html=./report/report.html --self-contained-html
#addopts = -v --reruns 1 --alluredir ./report/allure_raw
#addopts = -v -s -p no:warnings --reruns 1 --pytest_report ./report/Pytest_Report.html
pytest.ini
requirements.txt #存放导入依赖包(pip install -r requirements.txt安装依赖包)
allure-pytest==2.8.15
allure-python-commons==2.8.15
appdirs==1.4.4
APScheduler==3.6.3
atomicwrites==1.3.0
attrs==19.3.0
BeautifulReport==0.1.2
beautifulsoup4==4.8.1
black==19.10b0
certifi==2019.9.11
cffi==1.14.0
chardet==3.0.4
Click==7.0
colorama==0.4.3
colorlog==4.1.0
crypto==1.4.1
cryptography==2.9.2
filetype==1.0.7
Flask==1.1.1
har2case==0.3.1
HttpRunner==1.5.8
idna==2.8
importlib-metadata==1.6.0
itsdangerous==1.1.0
Jinja2==2.10.3
jmespath==0.9.5
loguru==0.4.1
lxml==4.5.0
MarkupSafe==1.1.1
more-itertools==8.2.0
Naked==0.1.31
numpy==1.17.4
packaging==20.3
parameterized==0.7.1
ParamUnittest==0.2
pathspec==0.8.0
Pillow==6.2.1
pluggy==0.13.1
py==1.8.1
pycparser==2.20
pycryptodome==3.9.4
pydantic==1.5.1
Pygments==2.6.1
PyMySQL==0.9.3
pyparsing==2.4.7
Pypubsub==4.0.3
pytest==5.4.2
pytz==2019.3
pywin32==227
PyYAML==5.1.2
regex==2020.5.14
requests==2.22.0
requests-toolbelt==0.9.1
robotframework==3.1.2
robotframework-ride==1.7.4.1
schedule==0.6.0
selenium==3.141.0
send-email==201212
shellescape==3.4.1
six==1.13.0
soupsieve==1.9.5
toml==0.10.1
typed-ast==1.4.1
tzlocal==2.0.0
urllib3==1.25.7
wcwidth==0.1.9
Werkzeug==0.16.0
win32-setctime==1.0.1
wxPython==4.0.7.post2
xlrd==1.2.0
zipp==3.1.0
requirements.txt
common/base.py #存放公共方法
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.select import Select
from selenium.webdriver.common.action_chains import ActionChains
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import NoSuchFrameException
from selenium.common.exceptions import StaleElementReferenceException
from selenium.common.exceptions import ElementNotVisibleException
from selenium.common.exceptions import TimeoutException
from common.log import Log
class LocatorTypeError(Exception):
pass
class ElementNotFound(Exception):
pass
class Base():
'''基于原生selenium二次封装'''
log = Log()
def __init__(self,driver:webdriver.Chrome,timeout = 10,t = 0.5):
url = "http://********"
self.base_url = url
self.driver = driver
self.timeout = timeout
self.t = t
def find(self, locator):
"""定位到元素,返回元素对象,没定位到,Timeout异常"""
if not isinstance(locator, tuple):
raise LocatorTypeError("参数类型错误,locator必须是元祖类型:loc = ('id','value1')")
else:
self.log.info("正在定位元素信息:定位方式->%s,value值->%s" % (locator[0], locator[1]))
#print("正在定位元素信息:定位方式->%s,value值->%s" % (locator[0], locator[1]))
try:
ele = WebDriverWait(self.driver, self.timeout, self.t).until(EC.presence_of_element_located(locator))
except TimeoutException as msg:
raise ElementNotFound("定位元素出现超时!")
return ele
def finds(self,locator):
'''复数定位,返回elements对象 list'''
if not isinstance(locator,tuple):
raise LocatorTypeError('参数类型错误,locator必须是元组类型:loc = ("id","value")')
else:
self.log.info("正在定位元素信息:定位方式->%s,value值->%s" % (locator[0], locator[1]))
#print("正在定位元素信息:定位方式->%s,value值->%s"%(locator[0],locator[1]))
try:
eles = WebDriverWait(self.driver, self.timeout, self.t).until(EC.presence_of_all_elements_located(locator))
except TimeoutException as msg:
raise ElementNotFound("定位元素出现超时!")
return eles
def writein(self,locator,text = ""):
'''写入文本'''
ele = self.find(locator)
if ele.is_displayed():
ele.send_keys(text)
else:
raise ElementNotVisibleException("元素不可见或者不唯一无法输入")
def click(self,locator):
'''点击元素'''
ele = self.find(locator)
if ele.is_displayed():
ele.click()
else:
raise ElementNotVisibleException("元素不可见或者不唯一无法点击")
def clear(self,locator):
'''清空输入框文本'''
ele = self.find(locator)
if ele.is_displayed():
ele.clear()
else:
raise ElementNotVisibleException("元素不可见或者不唯一")
def is_selected(self,locator):
'''判断元素是否被选中,返回bool值'''
ele = self.find(locator)
r = ele.is_selected()
return r
def is_element_exist(self,locator):
'''是否找到'''
try:
self.find(locator)
return True
except :
return False
def is_title(self,title = ""):
'''返回bool值'''
try:
result = WebDriverWait(self.driver,self.timeout,self.t).until(EC.title_is(title))
return result
except :
return False
def is_title_contains(self, title=''):
"""返回bool值"""
try:
result = WebDriverWait(self.driver, self.timeout, self.t).until(EC.title_contains(title))
return result
except:
return False
def is_text_in_element(self,locator,text = ''):
'''返回bool值'''
if not isinstance(locator,tuple):
raise LocatorTypeError("参数类型错误,locator必须是元祖类型:loc = ('id','value1')")
try:
result = WebDriverWait(self.driver, self.timeout, self.t).until(
EC.text_to_be_present_in_element(locator, text))
return result
except :
return False
def is_value_in_element(self,locator,value = ""):
if not isinstance(locator, tuple):
raise LocatorTypeError("参数类型错误,locator必须是元祖类型:loc = ('id','value1')")
try:
result = WebDriverWait(self.driver, self.timeout, self.t).until(
EC.text_to_be_present_in_element_value(locator, value))
return result
except:
return False
def is_alert(self,timeout = 8):
try:
result = WebDriverWait(self.driver, timeout, self.t).until(EC.alert_is_present())
return result
except:
return False
def get_title(self):
"""获取title"""
return self.driver.title
def get_text(self, locator):
"""获取文本"""
if not isinstance(locator, tuple):
raise LocatorTypeError("参数类型错误,locator必须是元祖类型:loc = ('id','value1')")
try:
t = self.find(locator).text
return t
except:
self.log.info("获取text失败,返回''")
#print("获取text失败,返回''")
return ""
def get_attribute(self, locator, name):
"""获取属性"""
if not isinstance(locator, tuple):
raise LocatorTypeError("参数类型错误,locator必须是元祖类型:loc = ('id','value1')")
try:
element = self.find(locator)
return element.get_attribute(name)
except:
self.log.info("获取%s属性失败,返回''" % name)
#print("获取%s属性失败,返回''" % name)
return ''
def js_focus_element(self,locator):
'''聚焦元素'''
if not isinstance(locator,tuple):
raise LocatorTypeError("参数类型错误")
target = self.find(locator)
self.driver.execute_script("arguments[0].scrollIntoView();", target)
def js_scroll_top(self):
'''滚到顶部'''
js = "window.scrollTo(0,0)"
self.driver.execute_script(js)
def js_scroll_end(self,x = 0):
'''滚到底部'''
js = "window.scrollTo(%s, document.body.scrollHeight)" % x
self.driver.execute_script(js)
def select_by_index(self,locator,index =0):
'''通过索引,index是索引第几个,从0开始,默认第一个'''
if not isinstance(locator,tuple):
raise LocatorTypeError("参数类型错误")
element = self.find(locator)
Select(element).select_by_index(index)
def select_by_value(self, locator, value):
"""通过value属性"""
if not isinstance(locator, tuple):
raise LocatorTypeError("参数类型错误")
element = self.find(locator)
Select(element).select_by_value(value)
def select_by_text(self,locator,text):
"""通过文本值定位"""
element = self.find(locator)
Select(element).select_by_visible_text(text)
def switch_iframe(self, id_index_locator):
"""切换iframe"""
try:
if isinstance(id_index_locator, int):
self.driver.switch_to.frame(id_index_locator)
elif isinstance(id_index_locator, str):
self.driver.switch_to.frame(id_index_locator)
elif isinstance(id_index_locator, tuple):
ele = self.find(id_index_locator)
self.driver.switch_to.frame(ele)
except:
self.log.info("iframe切换异常")
#print("iframe切换异常")
def switch_handle(self,window_name):
self.driver.switch_to.window(window_name)
def switch_alert(self):
r = self.is_alert()
if not r:
self.log.info("alert不存在")
#print("alert不存在")
else:
return r
def move_to_element(self, locator):
"""鼠标悬停操作"""
if not isinstance(locator, tuple):
raise LocatorTypeError("参数类型错误")
ele = self.find(locator)
ActionChains(self.driver).move_to_element(ele).perform()
if __name__ == '__main__':
driver = webdriver.Chrome()
web = Base(driver)
driver.get("https://www.baidu.com")
loc_1 = ("id", "kw")
web.writein(loc_1, "hello")
driver.close()
base.py
common/log.py #生成日志文件
import logging,time
import os
import getpathinfo
path = getpathinfo.get_path()#获取本地路径
log_path = os.path.join(path,'logs')# log_path是存放日志的路径
# 如果不存在这个logs文件夹,就自动创建一个
if not os.path.exists(log_path):os.mkdir(log_path)
class Log():
def __init__(self):
#文件的命名
self.logname = os.path.join(log_path,'%s.log'%time.strftime('%Y_%m_%d'))
self.logger = logging.getLogger()
self.logger.setLevel(logging.DEBUG)
#日志输出格式
self.formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
def __console(self,level,message):
#创建一个fileHander,用于写入本地
fh = logging.FileHandler(self.logname,'a',encoding='utf-8')
fh.setLevel(logging.DEBUG)
fh.setFormatter(self.formatter)
self.logger.addHandler(fh)
#创建一个StreamHandler,用于输入到控制台
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
ch.setFormatter(self.formatter)
self.logger.addHandler(ch)
if level == 'info':
self.logger.info(message)
elif level == 'debug':
self.logger.debug(message)
elif level == 'warning':
self.logger.warning(message)
elif level == 'error':
self.logger.error(message)
#避免日志重复
self.logger.removeHandler(fh)
self.logger.removeHandler(ch)
#关闭打开文件
fh.close()
def debug(self,message):
self.__console('debug',message)
def info(self,message):
self.__console('info',message)
def warning(self,message):
self.__console('warning',message)
def error(self,message):
self.__console('error',message)
if __name__ == '__main__':
log = Log()
log.info('测试')
log.debug('测试')
log.warning('测试')
log.error('测试')
log.py
common/read_yml.py #读取yml文件
import os
import yaml
import getpathinfo
class ReadYaml():
def __init__(self,filename):
path = getpathinfo.get_path()#获取本地路径
self.filepath = os.path.join(path,'data')+"/"+filename#拼接定位到data文件夹
def get_yaml_data(self):
with open(self.filepath,'r',encoding='utf-8')as f:
#调用load方法加载文件流
return yaml.load(f,Loader=yaml.FullLoader)
if __name__ == '__main__':
data = ReadYaml("login_page.yml").get_yaml_data()
username = data["test_login_element"][0]
print(tuple(username))
read_yml.py
pages #存放测试页面操作步骤、断言(写了简单两个)
from common.base import Base
from common.read_yml import ReadYaml
testelement = ReadYaml("login_page.yml").get_yaml_data()
class LoginPage(Base):
loc1 = tuple(testelement["test_login_element"][0])#用户名
loc2 = tuple(testelement["test_login_element"][1])#密码
loc3 = tuple(testelement["test_login_element"][2])#登录
# 判断元素
loc4 = tuple(testelement["test_login_element"][3])#登录成功断言
loc5 = tuple(testelement["test_login_element"][4])#登录失败断言
def input_username(self, text="admin"):
'''输入用户名'''
self.writein(self.loc1, text)
def input_password(self, text="yoyo123456"):
'''输入用户名'''
self.writein(self.loc2, text)
def click_button(self):
'''点击登录按钮'''
self.click(self.loc3)
def login(self, user="admin", password="yoyo123456"):
'''登录'''
self.driver.get(self.base_url)
self.input_username(user)
self.input_password(password)
self.click_button()
def is_login_success(self, expect_text='后台页面'):
text = self.get_text(self.loc4)
self.log.info("获取到断言元素的文本内容:%s"%text)
return expect_text == text
def is_login_fail(self, expect_text='请输入正确的用户名和密码'):
text = self.get_text(self.loc5)
self.log.info("获取到断言元素的文本内容:%s"%text)
return expect_text in text
if __name__ == '__main__':
from selenium import webdriver
driver = webdriver.Chrome()
web = LoginPage(driver)
web.login()
result = web.is_login_fail()
print("登录结果:", result)
assert result
driver.quit()
login_page.py
from common.base import Base
from common.read_yml import ReadYaml
testelement = ReadYaml("add_account_page.yml").get_yaml_data()
class Add_Account(Base):
loc1 = tuple(testelement["test_account_element"][0]) # 银行卡账户
loc2 = tuple(testelement["test_account_element"][1]) # 添加银行卡账户
loc3 = tuple(testelement["test_account_element"][2]) # 卡号
loc4 = tuple(testelement["test_account_element"][3]) # 姓名
loc5 = tuple(testelement["test_account_element"][4]) # 电话
loc6 = tuple(testelement["test_account_element"][5]) # 邮箱
loc7 = tuple(testelement["test_account_element"][6]) # 城市
loc8 = tuple(testelement["test_account_element"][7]) # 性别
loc9 = tuple(testelement["test_account_element"][8]) # 保存
loc10 = tuple(testelement["test_account_element"][9]) # 新增成功校验
loc11 = tuple(testelement["test_account_element"][10]) #账号为空校验
loc12 = tuple(testelement["test_account_element"][11]) #姓名为空校验
def click_account(self):
'''点击银行卡账号'''
self.finds(self.loc1)[0].click()
def click_add_account(self):
'''点击添加银行卡账号'''
self.click(self.loc2)
def input_card_num(self,text = "123456"):
'''输入卡号'''
self.writein(self.loc3,text)
def input_name(self,text = " "):
'''输入姓名'''
self.writein(self.loc4,text)
def input_phone(self,text = "123456"):
'''输入电话'''
self.writein(self.loc5,text)
def input_mail(self,text = "123456"):
'''输入邮箱'''
self.writein(self.loc6,text)
def input_city(self,text = "测试"):
'''输入城市'''
self.writein(self.loc7,text)
def input_sex(self,text = "男"):
'''输入性别'''
self.writein(self.loc8,text)
def click_save(self):
'''点击保存'''
self.click(self.loc9)
def is_add_success(self, expect_text='添加成功'):
text = self.get_text(self.loc10)
self.log.info("获取到断言元素的文本内容:%s" %text)
return expect_text in text
def is_add_fail1(self, expect_text='这个字段是必须的'):
'''账号为空断言'''
text = self.get_text(self.loc11)
self.log.info("获取到断言元素的文本内容:%s" %text)
return expect_text in text
def is_add_fail2(self, expect_text='这个字段是必须的'):
'''姓名为空断言'''
text = self.get_text(self.loc12)
self.log.info("获取到断言元素的文本内容:%s" %text)
return expect_text in text
if __name__ == '__main__':
from pages.login_page import LoginPage
from selenium import webdriver
driver = webdriver.Chrome()
driver.maximize_window()
web = LoginPage(driver)
web.login()
account = Add_Account(driver)
account.click_account()
account.click_add_account()
account.input_card_num()
account.input_name()
account.input_phone()
account.input_mail()
account.input_city()
account.input_sex()
account.click_save()
account.is_add_fail()
driver.quit()
add_account_page.py
case/conftest.py #存放前置操作,设置无界面模式
import platform
from selenium import webdriver
from pages.login_page import LoginPage
import pytest
import time
from common.log import Log
from selenium.webdriver.chrome.options import Options
log = Log()
@pytest.fixture(scope="session")
def login_fixtrue(driver):
#登录前置操作
#driver = webdriver.Chrome()
#driver.maximize_window()
web = LoginPage(driver)
web.login()
return driver
def pytest_addoption(parser):
'''添加命令行参数'''
parser.addoption('--headless', action = "store",
default = 'no', help = 'set chrome headless option yes or no'
)
@pytest.fixture(scope="session")
def driver(request):
"""定义全局driver fixture,给其它地方作参数调用"""
if platform.system()=='Windows':
chrome_options = Options()
chrome_options.add_argument('--window-size=1920,1080') # 设置当前窗口的宽度,高度
chrome_options.add_argument('--headless') # 无界面
print("当前运行的操作系统为windows")
_driver = webdriver.Chrome(chrome_options=chrome_options)
else:
print('当前运行的操作系统为linux')
chrome_options = Options()
chrome_options.add_argument('--window-size=1920,1080') # 设置当前窗口的宽度,高度
chrome_options.add_argument('--no-sandbox')#解决DevToolsActivePort文件不存在报错问题
chrome_options.add_argument('--disable-gpu')#禁用GPU硬件加速,如果软件渲染器没有就位,则GPU进程将不会启动
chrome_options.add_argument('--disable-dev-shm-usage')
chrome_options.add_argument('--headless') # 无界面
_driver = webdriver.Chrome(chrome_options=chrome_options)
def end():
print("全部用例执行完后 teardown quit dirver")
time.sleep(5)
_driver.quit()
request.addfinalizer(end)
return _driver
conftest.py
case/test_login.py #存放登录页面测试用例
import allure
import pytest
from common.log import Log
from common.read_yml import ReadYaml
from pages.login_page import LoginPage
from selenium import webdriver
testdata = ReadYaml('login_page.yml').get_yaml_data()#读取数据
class Test_login():
log = Log()
@allure.feature("功能点:用户登录页面")
@allure.story("用例:用户登录")
@pytest.mark.parametrize("username,password,msg",testdata["test_login_success_data"],
ids = ["正确用户名密码登录"])
@pytest.mark.skip('跳过该成功用例')
def test_success_login(self,driver,username,password,msg):
#driver = webdriver.Chrome()
web = LoginPage(driver)
web.login(user=username,password=password)
result = web.is_login_success(expect_text=msg)
self.log.info("登录结果:%s"%result)
assert result
#driver.quit()
@allure.feature("功能点:用户登录页面")
@allure.story("用例:用户登录")
@pytest.mark.parametrize("username,password,msg", testdata["test_login_fail_data"],
ids=["正确用户名错误密码登录",
"错误用户名正确密码登录"])
def test_fail_login(self,driver,username,password,msg):
#driver = webdriver.Chrome()
web = LoginPage(driver)
web.login(user=username,password=password)
result = web.is_login_fail(expect_text=msg)
self.log.info("登录结果:%s"%result)
assert result
test_login.py
case/test_add_account.py #存放添加账户页面测试用例
import allure
import pytest
from common.log import Log
from common.read_yml import ReadYaml
from pages.add_account_page import Add_Account
testdata = ReadYaml('add_account_page.yml').get_yaml_data()#读取测试数据
class Test_Add_Account():
log = Log()
@allure.feature("功能点:添加银行卡账户")
@allure.story("用例:添加银行卡账户")
@pytest.mark.parametrize("card_num,name,phone,mail,city,sex,msg",testdata["test_add_account_data1"],
ids=["正常添加"])
def test_add_account(self, login_fixtrue,card_num, name, phone,mail,city,sex,msg):
driver = login_fixtrue
account = Add_Account(driver)
with allure.step("点击银行卡账户,跳转添加账户页面"):
account.click_account()
with allure.step("点击添加账户按钮,进入编辑页面"):
account.click_add_account()
with allure.step("输入账户号"):
account.input_card_num(text=card_num)
with allure.step("输入姓名"):
account.input_name(text=name)
with allure.step("输入手机号"):
account.input_phone(text=phone)
with allure.step("输入邮箱"):
account.input_mail(text=mail)
with allure.step("输入城市"):
account.input_city(text=city)
with allure.step("输入性别"):
account.input_sex(text=sex)
with allure.step("点击保存"):
account.click_save()
with allure.step("获取结果: 获取页面实际结果,判断是否添加成功"):
result = account.is_add_success(expect_text=msg)
self.log.info("断言结果:%s"%result)
with allure.step("断言:判断是否添加成功"):
assert result == True
#driver.quit()
@allure.feature("功能点:添加银行卡账户")
@allure.story("用例:添加银行卡账户")
@pytest.mark.parametrize("card_num,name,phone,mail,city,sex,msg",testdata["test_add_account_data2"],
ids=["账号为空添加"])
def test_add_account1(self, login_fixtrue,card_num, name, phone,mail,city,sex,msg):
driver = login_fixtrue
account = Add_Account(driver)
with allure.step("点击银行卡账户,跳转添加账户页面"):
account.click_account()
with allure.step("点击添加账户按钮,进入编辑页面"):
account.click_add_account()
with allure.step("输入账户号"):
account.input_card_num(text=card_num)
with allure.step("输入姓名"):
account.input_name(text=name)
with allure.step("输入手机号"):
account.input_phone(text=phone)
with allure.step("输入邮箱"):
account.input_mail(text=mail)
with allure.step("输入城市"):
account.input_city(text=city)
with allure.step("输入性别"):
account.input_sex(text=sex)
with allure.step("点击保存"):
account.click_save()
with allure.step("获取结果: 获取页面实际结果,判断是否添加成功"):
result = account.is_add_fail1(expect_text=msg)
self.log.info("断言结果:%s"%result)
with allure.step("断言:判断是否添加成功"):
assert result == True
#driver.quit()
@allure.feature("功能点:添加银行卡账户")
@allure.story("用例:添加银行卡账户")
@pytest.mark.parametrize("card_num,name,phone,mail,city,sex,msg", testdata["test_add_account_data3"],
ids=["姓名为空添加"])
def test_add_account2(self, login_fixtrue, card_num, name, phone, mail, city, sex, msg):
driver = login_fixtrue
account = Add_Account(driver)
with allure.step("点击银行卡账户,跳转添加账户页面"):
account.click_account()
with allure.step("点击添加账户按钮,进入编辑页面"):
account.click_add_account()
with allure.step("输入账户号"):
account.input_card_num(text=card_num)
with allure.step("输入姓名"):
account.input_name(text=name)
with allure.step("输入手机号"):
account.input_phone(text=phone)
with allure.step("输入邮箱"):
account.input_mail(text=mail)
with allure.step("输入城市"):
account.input_city(text=city)
with allure.step("输入性别"):
account.input_sex(text=sex)
with allure.step("点击保存"):
account.click_save()
with allure.step("获取结果: 获取页面实际结果,判断是否添加成功"):
result = account.is_add_fail2(expect_text=msg)
self.log.info("断言结果:%s" % result)
with allure.step("断言:判断是否添加成功"):
assert result == True
# driver.quit()
test_add_account.py
data/add_account_page.yml #存放添加账户页面测试数据,定位元素
test_account_element:
- ["xpath",'//*[@href="/xadmin/hello/card/"]']
- ["xpath",'//*[@id="content-block"]/div[1]/div[2]/div/a']
- ["xpath",'//*[@id="id_card_id"]']
- ["xpath",'//*[@id="id_card_user"]']
- ["xpath",'//*[@id="id_carddetail-0-tel"]']
- ["xpath",'//*[@id="id_carddetail-0-mail"]']
- ["xpath",'//*[@id="id_carddetail-0-city"]']
- ["xpath",'//*[@id="id_carddetail-0-address"]']
- ["xpath",'//*[@id="card_form"]/div[2]/button']
- ["xpath",'//*[@id="content-block"]/div[2]']
- ["xpath",'//*[@id="error_1_id_card_id"]']
- ["xpath",'//*[@id="error_1_id_card_user"]']
test_add_account_data1:
- ["123456","秋水1","123456","123456","测试","男","添加成功"]
test_add_account_data2:
- [" ","秋水2","123456","123456","测试","男","这个字段是必须的"]
test_add_account_data3:
- ["123456"," ","123456","123456","测试","男","这个字段是必须的"]
add_account_page.yml
report/allure_raw #测试报告(运行命令:allure serve report/allure_raw)
记录完毕,生成allure报告在pytest.ini中有写,解开注释即可,pytest运行生成报告,或者pytest --alluredir ./report/allure_raw