测试学习记录,仅供参考!
优化断言结果
1、优化代码脚本,找到在项目根目录文件夹下 testcase 软件包 login 目录文件下 test.login.py 文件;
可以清楚的看到是把断言写到测试用例里面中去了,所以得优化代码,把断言中的"元素定位"放到页面类中去管理;
import pytest
from selenium.webdriver.common.by import By
from time import sleep
from pageObject.login_page.login_page import LoginPage
from util_tools.handle_data.operateJson import read_json
# from util_tools.handle_data.readYaml import read_yaml
# from util_tools.handle_data.operateExcel import ExcelDataReader
class TestLogin:
# 使用参数化实现一条测试用例跑多种场景--可迭代对象里面有多少组数据就跑多少次测试用例
@pytest.mark.parametrize('data', read_json('./data/login.json'))
# 用一个 data(需与上面保持一致) 参数去接收参数化数据
def test_login_success(self, get_driver, data):
# 进行列表解包--通过两个参数去接收列表中的数据
username, password = data
# 传浏览器对象--再把结果返回
login_page = LoginPage(get_driver)
# 直接调用页面类中的 login 操作--里面需要输入两个参数(参数化传两个参数)
login_page.login(username, password)
# 断言结果
success_ele = get_driver.find_element(By.XPATH, '//*[@id="ECS_MEMBERZONE"]/font/font')
assert success_ele != ''
sleep(2)
2、优化项目根目录文件 pageObject 软件包 login_page 目录文件下 login_page.py 文件内容;
from selenium.webdriver.common.by import By
from util_tools.basePage import BasePage
# 登录页面类
class LoginPage(BasePage):
url = 'http://localhost:8088/ecshop/user.php'
# 用户名
username = (By.NAME, 'username')
# 密码
password = (By.NAME, 'password')
# 登录按钮
submit = (By.NAME, 'submit')
# 断言结果
assert_result = (By.XPATH, '//*[@id="ECS_MEMBERZONE"]/font/font')
# 登录操作
def login(self, user_name, pass_word):
# 打开网址
self.open_url(self.url)
# 输入用户名
self.send_keys(self.username, user_name)
# 输入密码
self.send_keys(self.password, pass_word)
# 点击登录按钮
self.click(self.submit)
3、优化代码改造 test.login.py 文件中的断言结果;
4、这里可以重新写一个断言文件 ,封装成单独的一个类;(可按需自行选择)
在项目根目录文件夹下 util_tools 软件包下新建名称为 assertions.py 的 Python 文件,输入填写以下内容;
from util_tools.basePage import BasePage
class SeleniumAssertions(BasePage):
@staticmethod
def assert_element_text(element, expected_text):
"""
断言元素文本内容
:param element: 元素
:param expected_text: 文本
:return:
"""
actual_text = element.text
assert actual_text == expected_text, f"预期文本:{expected_text},实际文本:{actual_text}"
def assert_element_present(self, locator: tuple):
"""
断言元素是否存在
:param locator: 定位方式
:return:
"""
element = self.is_element_present(*locator)
assert element.is_displayed(), '元素不存在!'
5、 如若单独封装此断言元素结果的话,每次需要先引用导入才可以使用;而现在页面类 class LoginPage 已经继承了 BasePage 公共方法,所以只需要写到公共方法模块中就可以了,这里删除 assertions.py 文件;(自行选择是否单独封装)
6、开始优化项目根目录文件夹 util_tools 软件包下 basePage.py 文件内容;
# 导包
from pyxnat.core.uriutil import file_path
from selenium import webdriver
from selenium.common import NoSuchElementException
from selenium.webdriver.common.by import By
from time import sleep
from selenium.webdriver.support import expected_conditions as ec
from selenium.webdriver.support.wait import WebDriverWait
from config import setting
from util_tools.logs_util.recordlog import logs
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
from datetime import datetime
import pytesseract
from PIL import Image
class BasePage(object):
def __init__(self, driver):
self.__driver = driver
self.__wait = WebDriverWait(self.__driver, setting.WAIT_TIME)
def window_max(self):
self.__driver.maximize_window()
def window_full(self):
self.__driver.fullscreen_window()
def screenshot(self):
self.__driver.get_screenshot_as_png()
def open_url(self, url):
self.__driver.get(url)
@property
def current_url(self):
return self.__driver.current_url
@property
def title(self):
return self.__driver.title
def refresh(self):
self.__driver.refresh()
@property
def switch_to(self):
return self.__driver.switch_to
def iframe(self, frame):
self.switch_to.frame(frame)
def exit_iframe(self):
self.switch_to.default_content()
@property
def alert(self):
return self.__wait.until(ec.alert_is_present())
def alert_confirm(self):
self.alert.accept()
def alert_cancel(self):
self.alert.dismiss()
def location_element(self, by, value):
try:
element = self.__wait.until(ec.presence_of_element_located((by, value)))
logs.info(f"找到元素:{by}={value}")
return element
except Exception as e:
logs.error(f"未找到元素:{by}={value}")
raise e
def location_elements(self, by, value):
try:
self.__wait.until(ec.presence_of_all_elements_located((by, value)))
elements = self.__driver.find_elements(by, value)
logs.info(f"找到元素列表:{by}={value}")
return elements
except Exception as e:
logs.error(f"未找到元素列表:{by}={value}")
raise e
def click(self, locator: tuple, force=False):
try:
element = self.location_element(*locator)
if not force:
self.__driver.execute_script("arguments[0].click()", element)
else:
self.__driver.execute_script("arguments[0].click({force:true})", element)
logs.info(f"元素被点击:{locator}")
except NoSuchElementException as e:
logs.error(f"元素无法定位:{e}")
raise e
def send_keys(self, locator: tuple, data):
try:
element = self.location_element(*locator)
element.send_keys(data)
logs.info(f"元素被输入内容:{locator},输入的内容为:{data}")
except NoSuchElementException as e:
logs.error(f"元素无法定位:{e}")
raise e
def enter(self):
try:
ActionChains(self.__driver).send_keys(Keys.ENTER).perform()
logs.info("按下回车键")
except NoSuchElementException as e:
logs.error(f"元素无法定位:{e}")
raise e
def right_click(self, locator: tuple):
try:
element = self.location_element(*locator)
ActionChains(driver).context_click(element).perform()
logs.info("执行鼠标右键点击操作")
except NoSuchElementException as e:
logs.error(f"元素无法定位:{e}")
raise e
def double_click(self, locator: tuple):
try:
element = self.location_element(*locator)
ActionChains(driver).double_click(element).perform()
logs.info("执行鼠标双击操作")
except NoSuchElementException as e:
logs.error(f"元素无法定位:{e}")
raise e
def screenshots(self, image_name):
import os
current_time = datetime.now().strftime("%Y%m%d%H%M%S")
file_name = f"{image_name}-{current_time}.png"
file_path = os.path.join(setting.FILE_PATH.get('screenshot'), file_name)
self.__driver.get_screenshot_as_file(file_path)
def clear(self, locator: tuple):
try:
element = self.location_element(*locator)
element.clear()
logs.info("清空文本")
except NoSuchElementException as e:
logs.error(f"元素无法定位:{e}")
raise e
def ocr_captcha(self, locator: tuple):
captcha_element = self.location_element(*locator)
captcha_path = setting.FILE_PATH['screenshot'] + '/captcha.png'
captcha_element.screenshot(captcha_path)
captcha_image = Image.open(captcha_path)
try:
captcha_text = pytesseract.image_to_string(captcha_image)
logs.info(f"识别到的验证码为:{captcha_text}")
return captcha_text
except pytesseract.pytesseract.TesseractNotFoundError:
logs.error("找不到tesseract,这是因为pytesseract模块依赖于TesseractOCR引擎来进行图像识别!")
def assert_is_element_present(self, locator: tuple):
try:
element = self.__driver.find_element(*locator)
assert element.is_displayed(), '元素不存在'
except NoSuchElementException as e:
logs.error(f'元素未找到:{e}')
raise AssertionError('元素不存在')
def assert_title(self, expect_title):
assert expect_title in self.title
7、继续优化 test.login.py 文件内容;
1)、通过 login_page 这个页面类的对象去调用上面步骤中刚封装好的 is_element_present() 方法;
因为页面类 LoginPage 类继承了 BasePage 基类,所以可以直接调用 BasePage 基类里面的方法;
2)、可以通过 login_page 页面类这个对象去拿到断言结果 assert_result 定位方式;
import pytest
from selenium.webdriver.common.by import By
from time import sleep
from pageObject.login_page.login_page import LoginPage
from util_tools.handle_data.operateJson import read_json
# from util_tools.handle_data.readYaml import read_yaml
# from util_tools.handle_data.operateExcel import ExcelDataReader
class TestLogin:
# 使用参数化实现一条测试用例跑多种场景--可迭代对象里面有多少组数据就跑多少次测试用例
@pytest.mark.parametrize('data', read_json('./data/login.json'))
# 用一个 data(需与上面保持一致) 参数去接收参数化数据
def test_login_success(self, get_driver, data):
# 进行列表解包--通过两个参数去接收列表中的数据
username, password = data
# 传浏览器对象--再把结果返回
login_page = LoginPage(get_driver)
# 直接调用页面类中的 login 操作--里面需要输入两个参数(参数化传两个参数)
login_page.login(username, password)
# 断言结果
login_page.assert_is_element_present(login_page.assert_result)
sleep(2)
8、再次优化 test.login.py 文件内容之后可以看到断言结果更加简洁明了;
9、此时可以发现 data 文件目录下 login.json 文件中的有些数据一定会存在错误的(只有账号密码都对才是正确的);
[
{
"username": "admin123",
"password": "123456"
},
{
"username": "admin123456",
"password": "123456"
},
{
"username": "admin123",
"password": "123456789"
},
{
"username": "",
"password": ""
}
]
10、通过更改 data 文件目录下 login.json 的文件名称为 login_success.json 文件名(用于存放登录成功数据场景);
[
{
"username": "admin123",
"password": "123456"
}
]
11、在 data 文件目录下新建一个名称为 login_failed.json 的 Json 文件(存放登录失败数据场景);
[
{
"username": "admin123456",
"password": "123456"
},
{
"username": "admin123",
"password": "123456789"
},
{
"username": "admin123456",
"password": "123456789"
}
]
12、最后优化 test.login.py 文件,增加登录失败数据场景的测试用例,登录失败断言页面标题提示;
import pytest
from selenium.webdriver.common.by import By
from time import sleep
from pageObject.login_page.login_page import LoginPage
from util_tools.handle_data.operateJson import read_json
# from util_tools.handle_data.readYaml import read_yaml
# from util_tools.handle_data.operateExcel import ExcelDataReader
class TestLogin:
# 登录成功
# 使用参数化实现一条测试用例跑多种场景--可迭代对象里面有多少组数据就跑多少次测试用例
@pytest.mark.parametrize('data', read_json('./data/login_success.json'))
# 用一个 data(需与上面保持一致) 参数去接收参数化数据
def test_login_success(self, get_driver, data):
# 进行列表解包--通过两个参数去接收列表中的数据
username, password = data
# 传浏览器对象--再把结果返回
login_page = LoginPage(get_driver)
# 直接调用页面类中的 login 操作--里面需要输入两个参数(参数化传两个参数)
login_page.login(username, password)
# 断言结果
login_page.assert_is_element_present(login_page.assert_result)
sleep(2)
# 登录失败
@pytest.mark.parametrize('data', read_json('./data/login_failed.json'))
def test_login_failed(self, get_driver, data):
username, password = data
login_page = LoginPage(get_driver)
login_page.login(username, password)
login_page.assert_title('系统提示')
sleep(2)
13、运行主函数 run.py 文件查看结果(能够成功运行登录成功、登录失败场景);
未完待续。。。