从零开始搭建自动化测试工具:详细指南(三)

在之前的文章中,我们讨论了从零开始搭建自动化测试工具的技术选型,并展示了如何使用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进行自动化测试时,断言可以进一步扩展,包括文本内容的包含、不包含、不等于校验,甚至可以对页面元素的颜色、大小等属性进行校验。

后续我们将继续完善这个工具,增加测试报告等内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值