使用pytest+selenium+allure实现web页面自动化测试

测试文件

  • base 基本方法
  • data 测试数据
  • page web页面相关操作
  • image 测试截图
  • log 日志文件
  • report 测试报告文件
  • temp 临时文件
  • tool 文件读取,发邮件文件
  • TestCases 测试用例

在page下的__init__.py文件下配置

import os
import time
from selenium.webdriver.common.by import By

# 项目路径
PROJECT_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# 图片路径
IMAGE_PATH = os.path.join(PROJECT_PATH, 'image')
# 测试数据路径
DATA_PATH = os.path.join(PROJECT_PATH, 'data')
# 日志路径
LOG_PATH = os.path.join(PROJECT_PATH, 'log')
# 测试报告
REPORT_PATH = os.path.join(PROJECT_PATH, 'report', 'html')
# 临时文件
TEMP_PATH = os.path.join(PROJECT_PATH, 'temp')
# 请求url
url = "http://cal.apple886.com/"

"""  邮件信息  """
email_host = "smtp.qq.com"  # SMTP服务器
email_sender = '2022204437@qq.com'  # 发件人
email_license = 'jxyvidactsaiicja'  # 授权码
email_receivers = ['2022204437@qq.com']  # 收件人(可以群发)

""" 以下为测试数据配置文件 """
image_path = os.path.join(IMAGE_PATH, '%serror.png' % time.strftime("%Y%m%d%H%M%S"))

"""  以下为测试数据配置文件   """
add_data = os.path.join(DATA_PATH, 'add.json')
multi_data = os.path.join(DATA_PATH, 'multi.json')
subtr_data = os.path.join(DATA_PATH, 'subtr.json')

"""  以下为logger配置文件   """
log_filename = os.path.join(LOG_PATH, '%sdemo.log' % time.strftime("%Y%m%d%H%M%S"))
log_when = "midnight"
log_interval = 1
log_backupCount = 30
log_encoding = "utf-8"
log_filemode = "w"
log_format = "%(asctime)s -[%(name)s]- %(levelname)s---[%(filename)s [%(funcName)s:%(lineno)s]] - %(message)s"
log_datefmt = "%Y-%m-%d %H:%M:%S"

""""   以下为计算机配置数据   """
computer_add = By.XPATH, '//*[@id="simpleAdd"]'
computer_subtr = By.XPATH, '//*[@id="simpleSubtr"]'
computer_multi = By.XPATH, '//*[@id="simpleMulti"]'
computer_divi = By.XPATH, '//*[@id="simpleDivi"]'
computer_clear = By.XPATH, '//*[@id="simpleClearAllBtn"]'
computer_equal = By.XPATH, '//*[@id="simpleEqual"]'
computer_value = By.XPATH, '//*[@id="resultIpt"]'

在base下创建一个webpage.py文件

from selenium.webdriver.support.wait import WebDriverWait
from web.counter.base.logger import GetLogger
from web.counter import page

log = GetLogger().get_logger()


class WebPage:

    def __init__(self, driver):
        log.info("初始化driver{}".format(driver))
        self.driver = driver

    # 查找元素
    def base_find_element(self, loc, timeout=30, poll_frequency=0.5):
        log.info("正在查找元素{}".format(loc))
        return WebDriverWait(
            self.driver, timeout=timeout, poll_frequency=poll_frequency).until(
            lambda x: x.find_element(*loc))

    # 点击
    def base_click(self, loc):
        log.info("点击元素{}".format(loc))
        self.base_find_element(loc).click()

    # 输入
    def base_input(self, loc, key):
        log.info("输入元素{}输入值为{}".format(loc,key))
        self.base_find_element(loc).clear()
        self.base_find_element(loc).send_keys(key)

    # 获取文本
    def base_get_test(self, loc):
        log.info("获取文本{}".format(loc))
        return self.base_find_element(loc).text

    # 获取属性值
    def base_get_value(self, loc):
        log.info("获取{}属性值".format(loc))
        return self.base_find_element(loc).get_attribute('value')

    # 截图
    def base_get_image(self):
        log.error("错误!!!错误!!!错误!!!")
        self.driver.get_screenshot_as_file(page.image_path)

在base下创建一个driver.py文件

from selenium import webdriver
from web.counter import page


class GetDriver:
    driver = None

    @classmethod
    def get_driver(cls):
        if cls.driver is None:
            cls.driver = webdriver.Edge()
            cls.driver.maximize_window()
            cls.driver.get(page.url)
        return cls.driver

    @classmethod
    def quit_driver(cls):
        if cls.driver:
            cls.driver.quit()
            cls.driver = None

在base下创建一个logger.py文件

import logging.handlers
from web.counter import page


class GetLogger:
    logger = None

    @classmethod
    def get_logger(cls):
        if cls.logger is None:
            # 获取日志器
            cls.logger = logging.getLogger()
            # 获取日志器级别
            cls.logger.setLevel(logging.INFO)
            # 获取处理器 控制台
            sh = logging.StreamHandler()
            # 获取处理器 文件-以以时间分隔
            th = logging.handlers.TimedRotatingFileHandler(
                filename=page.log_filename,
                when=page.log_when,
                interval=page.log_interval,
                backupCount=page.log_backupCount,
                encoding=page.log_encoding)
            fm = logging.Formatter(page.log_format)
            sh.setFormatter(fm)
            th.setFormatter(fm)
            cls.logger.addHandler(th)
            cls.logger.addHandler(sh)
        return cls.logger

在page下创建一个add_page.py文件

from selenium.webdriver.common.by import By

from web.counter.base.webpage import WebPage
from web.counter import page


class AddPage(WebPage):
    # 点击数字
    def page_click_num(self, num):
        for n in str(num):
            loc = By.XPATH, '//*[@id="simple{}"]'.format(n)
            self.base_click(loc)

    # 点击加号
    def page_click_add(self):
        self.base_click(page.computer_add)

    # 点击等于
    def page_click_equal(self):
        self.base_click(page.computer_equal)

    # 获取结果
    def page_get_value(self):
        return self.base_get_value(page.computer_value)

    # 清屏
    def page_click_clear(self):
        self.base_click(page.computer_clear)

    # 截图
    def page_get_image(self):
        self.base_get_image()

    # 组装加法
    def page_add(self, a, b):
        self.page_click_num(a)
        self.page_click_add()
        self.page_click_num(b)
        self.page_click_equal()


在TestCases 下创建一个test_add.py文件

from time import sleep
import pytest
from web.counter.page.add_page import AddPage
from web.counter.base.driver import GetDriver
from web.counter.tool.read_json import GetJson
from web.counter.base.logger import GetLogger
from web.counter import page

log = GetLogger().logger


class TestAdd:

    def setup_class(self):
        self.computer = AddPage(GetDriver().get_driver())

    def teardown_class(self):
        GetDriver().quit_driver()

    @pytest.mark.parametrize("a, b, result", GetJson().get_data(page.add_data))
    def test_add_computer(self, a, b, result):
        self.computer.page_click_clear()
        self.computer.page_add(a, b)
        try:
            assert self.computer.page_get_value() == str(result)
        except:
            log.error("错误")
            sleep(1)
            self.computer.page_get_image()
            raise

在tool下创建一个read_json.py文件

import json


class GetJson:
    data_lists = None
    data_dic = None

    # 读取json文件
    @classmethod
    def read_json(cls, json_path):
        with open(json_path, "r", encoding="utf-8") as f:
            return json.load(f)

    # 获取测试数据
    @classmethod
    def get_data(cls, json_path):
        cls.data_dic = cls.read_json(json_path)
        cls.data_lists = list()
        for data in cls.data_dic.values():
            cls.data_lists.append((data.get("a"), data.get("b"), data.get("result")))
        return cls.data_lists

在tool下创建一个send_emails.py文件

import time
import zipfile
import os
from email.mime.application import MIMEApplication
from web.counter import page
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart


class SendEmails:
    def __init__(self):
        self.mime = MIMEMultipart()
        self.allure_report = None
        self.report_path = page.REPORT_PATH
        self.temp_path = page.TEMP_PATH

    def send_email(self):
        self.mime['Subject'] = '%sxxx测试报告' % time.strftime('%Y年%m月%d日 %H:%M:%S ')
        content = 'hello, this is email content.'
        textApart = MIMEText(content)
        zip_Apart = MIMEApplication(open(SendEmails().make_zip, 'rb').read())
        zip_Apart.add_header('Content-Disposition', 'attachment', filename='allure_report.zip')

        self.mime.attach(textApart)
        self.mime.attach(zip_Apart)
        try:
            server = smtplib.SMTP(page.email_host)
            server.login(page.email_sender, page.email_license)
            server.sendmail(page.email_sender, page.email_receivers, self.mime.as_string())
            print('发送成功')
            server.quit()
        except smtplib.SMTPException as e:
            print('error:', e)  # 打印错误

    # 打包目录为zip文件(实际未压缩)
    @property
    def make_zip(self):
        if not os.path.exists(self.temp_path):
            os.makedirs(self.temp_path)
        self.allure_report = os.path.join(self.temp_path, 'allure_report.zip')
        zip_file = zipfile.ZipFile(self.allure_report, 'w')
        for present, dirs, files in os.walk(self.report_path):
            """
                present:现在的目录
                dirs:该目录下包含的子目录
                files:该目录下包含的文件
            """
            for file in files:
                pathfile = os.path.join(present, file)
                relpath = os.path.relpath(pathfile, page.PROJECT_PATH)  # 相对路径
                # ZIP_STORED:实际上并未压缩。
                zip_file.write(pathfile, relpath, zipfile.ZIP_STORED)
        zip_file.close()
        return self.allure_report


if __name__ == '__main__':
    report = page.REPORT_PATH
    temp = page.TEMP_PATH
    print(report)
    print(temp)
    SendEmails().send_email()
    print(SendEmails().allure_report)
    print("压缩包创建完成")

# import zmail
# from web.counter import page
#
#
# def send_report():
#     """发送报告"""
#
#     with open(page.REPORT_PATH, encoding='utf-8') as f:
#         content_html = f.read()
#     try:
#         mail = {
#             'from': '2022204437@qq.com',
#             'subject': '最新的测试报告邮件',
#             'content_html': content_html,
#             'attachments': [page.REPORT_PATH, ]
#         }
#         server = zmail.server(*page.EMAIL_INFO.values())
#         server.send_mail(page.ADDRESSEE, mail)
#         print("测试邮件发送成功!")
#     except Exception as e:
#         print("Error: 无法发送邮件,{}!", format(e))
#
#
# if __name__ == "__main__":
#     '''请先在config/conf.py文件设置QQ邮箱的账号和密码'''
#     send_report()

web自动化大体就是这样,然后测试数据可以自己写

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/262698.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

再看参数校验

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO 联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬 写一个接口&#xff0c…

如何在Linux设置JumpServer实现无公网ip远程访问管理界面

文章目录 前言1. 安装Jump server2. 本地访问jump server3. 安装 cpolar内网穿透软件4. 配置Jump server公网访问地址5. 公网远程访问Jump server6. 固定Jump server公网地址 前言 JumpServer 是广受欢迎的开源堡垒机,是符合 4A 规范的专业运维安全审计系统。JumpS…

逆波兰计算器的完整代码

前置知识&#xff1a; 将中缀表达式转为List方法&#xff1a; //将一个中缀表达式转成中缀表达式的List//即&#xff1a;(3042)*5-6 》[(, 30, , 42, ), *, 5, -, 6]public static List<String> toIndixExpressionList(String s) {//定义一个List&#xff0c;存放中缀表达…

YACS(上海计算机学会竞赛平台)一星级题集——水仙花指数

题目描述 定义一个正整数的十进制表示中各位数字的立方和为它的水仙花指数&#xff0c;给定一个整数 n&#xff0c;请计算它的水仙花指数。 例如 n1234 时&#xff0c;水仙花指数为 输入格式 单个整数&#xff1a;表示 n 输出格式 单个整数&#xff1a;表示 n 的水仙花指…

深⼊理解指针

1. 内存和地址 1.1 内存 在讲内存和地址之前&#xff0c;我们想有个⽣活中的案例&#xff1a; 假设有⼀栋宿舍楼&#xff0c;把你放在楼⾥&#xff0c;楼上有100个房间&#xff0c;但是房间没有编号&#xff0c;你的⼀个朋友来找你玩&#xff0c; 如果想找到你&#xff0c;就…

嵌入式中的基本定时器

学习目标 理解基本定时器的作用掌握定时器开发流程掌握基本定时器中断处理的操作流程掌握AHB和APB时钟查询方式理解周期,分频系数,周期计数,分频计数。掌握调试策略学习内容 基本定时器 只能用于定时计时操作,没有输出引脚通道的定时器,在GD32中, TIMER5和TIMER6为基本…

Ubuntu 常用命令之 reboot 命令用法介绍

&#x1f4d1;Linux/Ubuntu 常用命令归类整理 reboot命令在Ubuntu系统中用于重新启动系统。这个命令通常需要管理员权限才能执行。 reboot命令的参数如下 -f 或 --force&#xff1a;强制重启&#xff0c;不调用shutdown -r进行友好重启。-p 或 --poweroff&#xff1a;在重启…

百度地图添加查询框

<div style"display:inline;float:left;margin: 10px"><el-input style"width: 400px" placeholder"输入地点" v-model"area" class"input-with-select"keyup.enter.native"searchMap"><el-button…

随机问卷调查数据的处理(uniapp)

需求&#xff1a;问卷调查 1.返回的数据中包含单选、多选、多项文本框、单文本框、图片上传 2.需要对必填的选项进行校验 3.非必填的多项文本框内容 如果不填写 不提交 表单数据格式 res{"code": 0,"msg": null,"data": [{"executeDay&…

lamda表达式(史上最全)

一、函数式接口 在jdk8中什么是函数式接口&#xff1a; 被FunctionalInterface注解修饰的。接口里边只有一个非default的方法。 满足以上2个条件的即为函数式接口&#xff0c;ps&#xff1a;即使一个接口没有FunctionalInterface修饰&#xff0c;但是满足2&#xff0c;那么这…

国产低成本Wi-Fi SoC解决方案芯片ESP8266与ESP8285对比差异

目录 ESP8266与ESP8285对比差异微信号&#xff1a;dnsj5343ESP8285简介ESP8285 主要特性Wi-Fi特性射频模块CPU特性硬件软件 ES8285 8266通用开发板 ESP8266与ESP8285对比差异 ESP8285相当于在ESP8266基础上多加了1/2MB Flash&#xff0c; ESP8285与ESP8266同用一套SDK&#xf…

异方差与多重共线性对回归问题的影响

异方差的检验 1.异方差的画图观察 2.异方差的假设检验&#xff0c;假设检验有两种&#xff0c;一般用怀特检验使用方法在ppt中&#xff0c;课程中也有实验&#xff0c;是一段代码。 异方差的解决办法 多重共线性 多重共线性可能带来的影响&#xff1a; 多重共线性的检验 多重…

德思特方案 | 德思特毫米波RIS研究测试方案:一站式助力工程师探索高频通信未来

来源&#xff1a;德思特测试测量 德思特方案 | 德思特毫米波RIS研究测试方案&#xff1a;一站式助力工程师探索高频通信未来 原文链接&#xff1a;德思特方案 | 德思特毫米波RIS研究测试方案&#xff1a;一站式助力工程师探索高频通信未来 欢迎关注虹科&#xff0c;为您提供最…

KubeSphere应用【五】发布镜像至Harbor

一、IDEA发布镜像至Docker 1.1IDEA安装Docker插件 1.2配置Docker服务器地址 1.3编写POM.XML文件 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/20…

Java学习常用实用类2

1 StringTokenizer类 字符串分析器&#xff0c;能够从一个字符串中根据指定的分隔符拆分出若干单词 StringTokenizer(String s) 使用默认分隔符集合&#xff0c;即&#xff1a;空格符、换行符、回车符、Tab符、进纸符 StringTokenizer(String s, String delim) 指定分…

cilium原理之ebpf尾调用与trace

背景 在深入剖析cilium原理之前&#xff0c;有两个关于epbf的基础内容需要先详细介绍一下&#xff1a; 1. ebpf尾调用 尾调用类似于程序之间的相互跳转&#xff0c;但它的功能更加强大。 2. trace 虽然之前使用trace_printk输出日志&#xff0c;但这个函数不能多用&#x…

数据仓库-数据治理小厂实践

一、简介 数据治理贯穿数仓中数据的整个生命周期&#xff0c;从数据的产生、加载、清洗、计算&#xff0c;再到数据展示、应用&#xff0c;每个阶段都需要对数据进行治理&#xff0c;像有些比较大的企业都是有自己的数据治理平台或者会开发一些便捷的平台&#xff0c;对于没有平…

从DevOps状态报告看技术团队的文化建设

本文源自一次内部分享&#xff0c;借由此机会又把历年的DevOps状态报告翻看了一遍&#xff0c;其实大多数时候我们对于DevOps的理解都在于流程&#xff0c;工具&#xff0c;实践这些看得见摸得着的东西&#xff0c;但就像文末的几点思考所说的那样&#xff0c;我们一直相信技术…

轴承故障诊断分类模型全家桶-最全教程

Python轴承故障诊断 (一)短时傅里叶变换STFT-CSDN博客 Python轴承故障诊断 (二)连续小波变换CWT-CSDN博客 Python轴承故障诊断 (三)经验模态分解EMD-CSDN博客 Pytorch-LSTM轴承故障一维信号分类(一)-CSDN博客 Pytorch-CNN轴承故障一维信号分类(二)-CSDN博客 Pytorch-Trans…

VM Group

在复杂方案中模块过多可能造成查看或修改方案时存在视觉混乱&#xff0c;不够直观。此时可利用Group模块进行模块整合&#xff0c;同时Group模式也兼容循环的功能&#xff0c;如下图所示。 双击Group模块可进入Group内部&#xff0c;如下图所示。 在Group模块单击 可设置输入、…