PO模式登录测试

news2024/7/4 20:06:24

项目实践

登陆项目测试

get_driver

import page
from selenium import webdriver


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

get_logger

import logging.handlers


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="../log/login.log",
                                                           when="midnight",
                                                           interval=1,
                                                           backupCount=3,
                                                           encoding="utf-8")

            fmt = '%(asctime)s %(levelname)s [%(name)s] [%(filename)s(%(funcName)s:%(lineno)d)] - %(message)s'
            fm = logging.Formatter(fmt)

            sh.setFormatter(fm)
            th.setFormatter(fm)

            cls.logger.addHandler(sh)
            cls.logger.addHandler(th)

        return cls.logger

base

from selenium.webdriver.support.wait import WebDriverWait
import time

from base.get_logger import GetLogger


log = GetLogger().get_logger()


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

    def base_find_element(self, loc, timeout=30, poll=0.5):
        log.info("正在查找元素{}".format(loc))
        return WebDriverWait(self.driver, timeout=timeout, poll_frequency=poll).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, value):
        log.info("正在给元素输入内容{}".format(loc))
        el = self.base_find_element(loc)
        # 清空
        log.info("正在给元素{}清空".format(loc))
        el.clear()
        # 输入
        log.info("正在给元素{}输入内容".format(loc))
        el.send_keys(value)

    def base_get_text(self, loc):
        # 注意:一定要返回元素的文本信息
        log.info("正在获取元素{}文本".format(loc))
        return self.base_find_element(loc).text

    # 截图
    def base_get_screen_shot(self):
        self.driver.get_screenshot_as_file("../image/{}.png".format(time.strftime("%Y_%m_%d %H_%M_%S")))

    # 封装判断元素是否存在
    def base_if_exist(self, loc):
        try:
            self.base_find_element(loc, timeout=2)
            log.info("元素{}存在".format(loc))

            return True
        except:
            log.info("元素{}不存在".format(loc))
            return False

__init__

from selenium.webdriver.common.by import By

"""项目配置地址"""
url = "https://demo5.tp-shop.cn/"

"""以下为登录页面元素配置信息"""

# 用户名
login_username = By.ID, "username"
# 密码
login_pwd = By.ID, "password"
# 验证码
login_verify_code = By.ID, "verify_code"
# 登录按钮
login_btn = By.CSS_SELECTOR, ".J-login-submit"
# 获取异常文本信息
login_err_info = By.CSS_SELECTOR, ".layui-layer-content"
# 点击异常提示框 按钮
login_err_btn_ok = By.CSS_SELECTOR, ".layui-layer-btn0"
# 安全退出
login_logout = By.PARTIAL_LINK_TEXT, "安全退出"

# 登录链接
login_link = By.PARTIAL_LINK_TEXT, "登录"

page_login 继承Base

from base.base import Base
import page


class PageLogin(Base):
    # 点击登录链接
    def page_click_login_link(self):
        self.base_click(page.login_link)

    # 输入用户名
    def page_input_username(self, username):
        self.base_input(page.login_username, username)

    # 输入密码
    def page_input_password(self, pwd):
        self.base_input(page.login_pwd, pwd)

    # 输入验证
    def page_input_verify_code(self, code):
        self.base_input(page.login_verify_code, code)

    # 点击登录按钮
    def page_click_login_btn(self):
        self.base_click(page.login_btn)

    # 获取异常提示信息
    def page_get_error_info(self):
        return self.base_get_text(page.login_err_info)

    # 点击异常信息框 确定
    def page_click_err_btn_ok(self):
        self.base_click(page.login_err_btn_ok)

    # 截图
    def page_get_img(self):
        self.base_get_screen_shot()

    # 点击 安全退出 --》退出使用
    def page_click_logout(self):
        self.base_click(page.login_logout)

    # 判断是否登录成功
    def page_is_login_success(self):
        return self.base_if_exist(page.login_logout)

    # 判断是否退出成功
    def page_is_logout_success(self):
        return self.base_if_exist(page.login_link)

    # 组合业务方法
    def page_login(self, username, pwd,code):
        self.page_input_username(username)
        self.page_input_password(pwd)
        self.page_input_verify_code(code)
        self.page_click_login_btn()

数据准备

json:

{
    "login_001":{"username":"138000011112",
               "password":"123456",
               "verify_code":"8888",
               "expect_result":"账号不存在!",
                "success": false},
    "login_002":{"username":"13800001111",
               "password":"1234567",
               "verify_code":"8888",
               "expect_result":"密码错误!",
                "success": false},
    "login_003":{"username":"",
               "password":"123456",
               "verify_code":"8888",
               "expect_result":"用户名不能为空!",
                "success": false},
    "login_004":{"username":"13800001111",
               "password":"",
               "verify_code":"8888",
               "expect_result":"密码不能为空!",
                "success": false},
    "login_005":{"username":"13800001111",
               "password":"123456",
               "verify_code":"",
               "expect_result":"验证码不能为空!",
                "success": false},
    "login_006":{"username":"13800001111",
               "password":"123456",
               "verify_code":"8888",
               "expect_result":"安全退出",
                "success": true}
}

txt:

138000011112,123456,8888,账号不存在!,false
13800001111,1234567,8888,密码错误!,false
,123456,8888,用户名不能为空!,false
13800001111,,8888,密码不能为空!,false
13800001111,123456,,验证码不能为空!,false
13800001111,123456,8888,安全退出,true

数据驱动方法

json:

# 导包
import json


def read_json(filename):
    filepath = "../data/" + filename
    # 打开文件并调用 load方法
    with open(filepath, "r", encoding="utf-8")as f:
        return json.load(f)

txt:

def read_txt(filename):
    filepath = "../data/" + filename
    with open(filepath, "r", encoding="utf-8")as f:
        return f.readlines()


业务层

# 导包
import unittest
from time import sleep

from base.get_driver import GetDriver
from page.page_login import PageLogin
from parameterized import parameterized
from tool.read_json import read_json
from tool.read_txt import read_txt
from base.get_logger import GetLogger


log = GetLogger().get_logger()


def get_data():
    arr = []
    for data in read_json("login.json").values():
        arr.append((data.get("username"),
                    data.get("password"),
                    data.get("verify_code"),
                    data.get("expect_result"),
                    data.get("success")))
    return arr  # 注意:必须进行return 返回

# def get_data():
#     arr = []
#     for data in read_txt("login.txt"):
#         arr.append(tuple(data.strip().split(",")))
#     return arr


# 新建测试类
class TestLogin(unittest.TestCase):
    login = None

    @classmethod
    def setUpClass(cls):
        try:
            # 实例化 获取页面对象 PageLogin
            cls.login = PageLogin(GetDriver().get_driver())
            # 点击登录连接
            cls.login.page_click_login_link()
        except Exception as e:
            log.error(e)

    # tearDown
    @classmethod
    def tearDownClass(cls):
        sleep(3)
        # 关闭 driver驱动对象
        GetDriver().quit_driver()

    def tearDown(self):
        self.login.driver.refresh()

    # 登录测试方法
    @parameterized.expand(get_data())
    def test_login(self, username, pwd, code, expect_result, success):
        # 调用登录方法
        self.login.page_login(username, pwd, code)
        if success:
            try:
                # 判断安全退出是否存在
                self.assertTrue(self.login.page_is_login_success())
                # 点击退出
                self.login.page_click_logout()
                try:
                    # 判断登录是否存在
                    self.assertTrue(self.login.page_is_logout_success)
                except:
                    # 截图
                    self.login.page_get_img()
                # 点击登录连接
                self.login.page_click_login_link()
            except Exception as e:
                # 截图
                self.login.page_get_img()
                log.error(e)
        else:
            # 获取登录提示信息
            msg = self.login.page_get_error_info()
            try:
                # 断言
                self.assertEqual(msg, expect_result)

            except AssertionError:
                # 截图
                self.login.page_get_img()
            # 点击 确认框
            self.login.page_click_err_btn_ok()

生成测试报告 

from tool.HTMLTestRunner import HTMLTestRunner
import unittest

suite = unittest.defaultTestLoader.discover("./", "test_login.py")
# 网页要wb
with open("../report/report_html.html", "wb") as f:
    HTMLTestRunner(stream=f).run(suite)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

gin框架 gin.Context中的Abort方法使用注意事项 - gin框架中立刻中断当前请求的方法

gin框架上下文中的Abort序列方法(Abort,AbortWithStatus, AbortWithStatusJSON,AbortWithError)他们都不会立刻终止当前的请求,在中间件中调用Abort方法后中间件中的后续的代码会被继续执行,但是…

Spring之spring的单例bean是线程安全的吗

Spring单例bean是线程安全的吗? 不是线程安全的。 1、Bean的作用域 Service Scope("singleton") public class UserServiceImpl implements UserService{ } singleton (默认):bean在每个Spring IOC容器中只有一个实例…

【有为己之心方能克己】

私欲会让人难受,为了自己舒服而去拔除,去除私欲小我,就可以为自己展现大我 “人不为己天诛地灭”,其实这句话不是自私自利的意思, 原意是:人如果不修为自己,不为那个真己而活,不活出…

LSH算法:高效相似性搜索的原理与Python实现I

局部敏感哈希(LSH)技术是快速近似最近邻(ANN)搜索中的一个关键方法,广泛应用于实现高效且准确的相似性搜索。这项技术对于许多全球知名的大型科技公司来说是不可或缺的,包括谷歌、Netflix、亚马逊、Spotify…

【工具】VS Code使用global插件实现代码跳转

🐚作者简介:花神庙码农(专注于Linux、WLAN、TCP/IP、Python等技术方向)🐳博客主页:花神庙码农 ,地址:https://blog.csdn.net/qxhgd🌐系列专栏:善假于物&#…

干货分享:代理IP的10大误区

在当今的数字时代,代理已成为在线环境不可或缺的一部分。它们的用途广泛,从增强在线隐私到绕过地理限制。然而,尽管代理无处不在,但仍存在许多围绕代理的误解。在本博客中,我们将探讨和消除一些最常见的代理误解&#…

EcoVadis评分标准是什么?

EcoVadis评分标准是一个综合性的评估体系,旨在评估公司在环境、社会、商业道德和可持续采购等方面的表现,以帮助企业提高可持续发展的能力。其评分标准可以根据不同的评级进行细分,以下是详细的评分标准: 评分等级与分数范围&…

comfyui定制

🌟 comfyui定制AI人工智能公司— 触站AI,绘制智能图像新纪元 🎨 🚀AI绘画,触站AI引领创新潮流 🚀深圳,这座创新之城,迎来了触站AI,一家专注于企业AI图像领域的技术解决方…

昇思25天学习打卡营第7天|Pix2Pix实现图像转换

文章目录 昇思MindSpore应用实践基于MindSpore的Pix2Pix图像转换1、Pix2Pix 概述2、U-Net架构定义UNet Skip Connection Block 2、生成器部分3、基于PatchGAN的判别器4、Pix2Pix的生成器和判别器初始化5、模型训练6、模型推理 Reference 昇思MindSpore应用实践 本系列文章主要…

Unity 动画事件

Unity中的动画事件是一种在动画播放过程中触发自定义行为的方法。动画事件允许开发者在动画的特定时间点执行代码,例如播放声音、改变游戏状态或触发其他动画。以下是使用Unity动画事件的一些关键点: 动画事件的创建:在Unity的Animation窗口…

Hadoop3:Yarn的Tool接口案例

一、需求 依然以wordcount案例为基础,进行开发 我们知道,用hadoop自带的example.jar执行wordcount 命令如下 hadoop jar /opt/module/hadoop-3.1.3/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.3.jar wordcount -D mapreduce.job.queuename…

973. 最接近原点的 K 个点-k数组维护+二分查找

973. 最接近原点的 K 个点-k数组维护二分查找 给定一个数组 points ,其中 points[i] [xi, yi] 表示 X-Y 平面上的一个点,并且是一个整数 k ,返回离原点 (0,0) 最近的 k 个点。 这里,平面上两点之间的距离是 欧几里德距离&#…

【Rust入门教程】hello world程序

文章目录 前言Hello World程序运行总结 前言 对于学习任何一种新的编程语言,我们都会从编写一个简单的Hello World程序开始。这是一个传统,也是一个开始。在这篇文章中,我们将一起学习如何在Rust中编写你的第一个程序:Hello Worl…

干货分享|如何将前端代理服务器(BFF)接入身份认证(2)

续集2 前篇文章在前面发布,同学们可以自行找一下。 本篇文章将继续通过实例来详细讲解如何将前端代理服务器(BFF)接入身份认证。我们将使用一个示例应用来演示 BFF 与身份认证的集成过程。 1)在 Keycloak 中新建一个安全领域 …

红队工具Finger 安装具体以步骤-示例centos

1.git clone https://github.com/EASY233/Finger.git 如果没有 yum install git 2.pip3 install -r requirements.txt 找到finger所在的文件夹 可以用find -name "Finger"进入文件中配置命令 前提要安装python yum install python-pip33.python3 Finger.py -h

中国AI产业迎来标准化大跃进,程序员们准备好了吗

中国AI产业迎来标准化大跃进,程序员们准备好了吗? 程序员们,你们是否已经感受到了人工智能技术的浪潮?现在,中国工信部联合其他部门发布了《国家人工智能产业综合标准化体系建设指南(2024版)》&…

龙迅LT8641UXE HDMI四进一出切换开关,支持标准HDMI 2.0内置MCU

龙迅LT8641UXE描述: Lontium LT8641UX HDMI2.0开关具有符合HDMI2.0/1.4规范的4:1开关,最大6Gbps高速数据速率,自适应均衡RX输入和预先强调的TX输出支持长电缆应用,没有XTAL板上节省BOM成本。LT8641UX HDMI2.0开关自动…

如何获取音频伴奏

如何获取音频伴奏 在今天的互联网上,有许多好听的音乐.面对这些音乐,我们有时需要伴奏音频,许多音频在网站上可以查找到,但有些不行,今天,我们要通过audacity软件截取音频伴奏. 下载audacity软件 audacity-64.exe 访问密码:8221 或官方网站(访问较慢) 选择简体…

LLM指令微调Prompt的最佳实践(二):Prompt迭代优化

文章目录 1. 前言2. Prompt定义3. 迭代优化——以产品说明书举例3.1 产品说明书3.2 初始Prompt3.3 优化1: 添加长度限制3.4 优化2: 细节纠错3.5 优化3: 添加表格 4. 总结5. 参考 1. 前言 前情提要: 《LLM指令微调Prompt的最佳实践(一)&#…

时序约束(二): input delay约束和output delay约束

一、input delay约束 在千兆以太网数据收发项目中,RGMII的数据输入方式为DDR,源同步输入方式,可以用之前提到的分析模型进行约束。 在时序约束原理中我们提到,input delay约束的就是发射沿lunch到数据有效的延时,根据…