在之前的文章中,我们讨论了从零开始搭建自动化测试工具的技术选型,并展示了如何使用Pytest-BDD框架、Selenium和Requests库来统一UI和接口自动化测试,同时利用Gherkin语言编写测试用例。本文将进一步介绍如何封装日志工具和断言工具,以便更有效地记录测试行为和验证测试结果。
日志封装
我们使用Python标准库中的logging
模块进行日志系统的封装,以便灵活记录测试过程中的关键信息。
import logging
from logging.handlers import RotatingFileHandler
def setup_logging(name, log_level=logging.DEBUG, max_bytes=1024 * 1024 * 5, backup_count=5):
"""
配置日志系统。
:param name: logger名称。
:param log_level: 日志级别,默认为INFO。
:param max_bytes: 日志文件达到此大小时进行轮转,默认为5MB。
:param backup_count: 保留的备份文件个数,默认为5个。
"""
# 创建一个logger
logger = logging.getLogger(name)
logger.setLevel(log_level)
# 创建一个handler,用于写入日志文件
handler = RotatingFileHandler('app.log', maxBytes=max_bytes, backupCount=backup_count)
handler.setLevel(log_level)
# 创建一个handler,用于输出到控制台
console_handler = logging.StreamHandler()
console_handler.setLevel(log_level)
# 定义handler的输出格式
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
console_handler.setFormatter(formatter)
# 给logger添加handler
logger.addHandler(handler)
logger.addHandler(console_handler)
return logger
# 使用示例
if __name__ == '__main__':
# 配置日志
logger = setup_logging(logging.DEBUG)
# 记录日志
logger.debug('这是一个debug级别的日志')
logger.info('这是一个info级别的日志')
logger.warning('这是一个warning级别的日志')
logger.error('这是一个error级别的日志')
logger.critical('这是一个critical级别的日志')
上述代码中,日志文件是写死在代码中的,完全可以提出来,将日志文件保存路径写到配置文件中。
断言工具
接口测试断言工具
针对接口测试,我们实现了多种断言方式,并通过一个字典来管理这些断言类型。
test_result_type_list = {
'相等校验': 0,
'包含校验': 1,
'字段类型校验': 2,
'字段值校验': 3,
'状态码校验': 4
}
接下来,我们实现这5种校验方式的编码
import json
from requests import Response
def assert_tool(self, response, test_result):
if type(response) is dict:
response_body = response
else:
response_body = response.text
text = test_result['test_result']['text']
types = test_result['test_result']['type']
type_map = {
'int': int,
'float': float,
'str': str,
'list': list,
'dict': dict,
'bool': bool,
}
if types == 0:
self.assertEqual(text, str(response_body), '接口返回与预期相等校验不通过')
elif types == 1:
self.assertIn(text, str(response_body), '接口返回与预期包含校验不通过')
elif types == 2:
result_type = test_result['test_result']['result_type']
key_str = test_result['test_result']['key']
self.assertIsInstance(analysis_dict(json.loads(response_body), key_str), type_map.get(result_type), '接口返回的数据类型与预期类型不符')
elif types == 3:
key_str = test_result['test_result']['key']
self.assertEqual(text, str(analysis_dict(json.loads(response_body), key_str)), '接口返回字段' + key_str + '的值,与预期相等校验不通过')
elif types == 4:
if type(response) is Response:
status = response.status_code
self.assertEqual(text, status, '接口返回状态码与预期结果相等校验不通过')
else:
self.assertEqual(text, str(response_body), '接口返回状态码与预期结果相等校验不通过')
def analysis_dict(response: dict, key_str):
if key_str in response:
return response[key_str]
for key, value in response.items():
if isinstance(value, dict):
result = analysis_dict(value, key_str)
if result is not None:
return result
elif isinstance(value, list):
for item in value:
if isinstance(item, dict):
result = analysis_dict(item, key_str)
if result is not None:
return result
return None
上述代码中,analysis_dict
函数是根据key值,去返回的response中遍历对应的value,主要是为了复杂的返回数据中,校验数据的值和类型使用。
selenium断言工具
以下是一个使用 Python 封装的 Selenium 断言工具:
from selenium.webdriver.remote.webdriver import WebDriver
class SeleniumAssertTool:
def __init__(self, driver: WebDriver):
self.driver = driver
def assert_element_exists(self, by, value):
"""
断言元素存在。
:param by: 定位方式,如 By.ID、By.XPATH 等。
:param value: 定位值。
"""
elements = self.driver.find_elements(by, value)
assert len(elements) > 0, f"元素 {by}={value} 不存在。"
def assert_element_text_equals(self, by, value, expected_text):
"""
断言元素的文本与预期文本相等。
:param by: 定位方式。
:param value: 定位值。
:param expected_text: 预期文本。
"""
element = self.driver.find_element(by, value)
actual_text = element.text
assert actual_text == expected_text, f"元素 {by}={value} 的文本不是预期的。实际文本:{actual_text},预期文本:{expected_text}"
def assert_url_equals(self, expected_url):
"""
断言当前页面的 URL 与预期 URL 相等。
:param expected_url: 预期 URL。
"""
actual_url = self.driver.current_url
assert actual_url == expected_url, f"当前 URL 不是预期的。实际 URL:{actual_url},预期 URL:{expected_url}"
使用示例:
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
assert_tool = SeleniumAssertTool(driver)
driver.get("https://www.example.com")
# 断言元素存在
assert_tool.assert_element_exists(By.ID, "some_element_id")
# 断言元素文本
assert_tool.assert_element_text_equals(By.CLASS_NAME, "some_class_name", "Expected Text")
# 断言 URL
assert_tool.assert_url_equals("https://www.example.com")
driver.quit()
结语
本文仅为一个初步的探索,旨在为读者提供一个关于断言和日志记录的基本思路。在实际项目中,断言和日志记录的具体实现方式需根据项目的具体需求进行调整。例如,在使用Selenium进行自动化测试时,断言可以进一步扩展,包括文本内容的包含、不包含、不等于校验,甚至可以对页面元素的颜色、大小等属性进行校验。
后续我们将继续完善这个工具,增加测试报告等内容。