使用python unittest从零构建web应用的自动化测试用例

news2024/9/20 13:53:14

文章目录

  • 必要性
  • 使用pycharm搭建unittest框架
  • selenium
    • 下载web driver
    • web driver的基本使用
    • driver 定位元素
    • driver使用事件
    • 处理下拉框
    • 处理复选框
  • ssh
  • ftp
  • 数据库
    • sqlserver
    • oracle
      • 安装
      • 使用
    • mongodb
  • excel
  • pycurl

必要性

大部分团队起始对于要不要投入资源进行UI自动化测试的开发都是持怀疑态度,特别是小型公司,觉得投入的产出比不成正比。
我自己的判断是基于下面几个考虑(基于小软件企业,中大型的另说):

  1. 做产品的公司可以考虑,做项目(外包)的公司一般不考虑,除非已经将一些组件抽象的非常high level,相对固定了。
  2. 产品中相对稳定的固定流程,在整个团队中消耗了较多测试人力的流程可以考虑使用UI测试化来替代。
  3. 产品最起码还有2-3年或者更长的生命周期,否则也不考虑。
  4. 投入的测试人力基本上是属于流程化作业。
  5. 从某个点开始做起,不要一开始就说要覆盖多少多少业务。

使用pycharm搭建unittest框架

pycharm环境默认支持unittest项目的创建。

  1. 创建一个python项目
  2. 在项目上右键创建一个python文件,选择Python unit test
    在这里插入图片描述
  3. 创建出来的文件为:
import unittest


class MyTestCase(unittest.TestCase):
    def test_something(self):
        self.assertEqual(True, False)


if __name__ == '__main__':
    unittest.main()
- MytestCase为测试类
- test_something为测试用例函数
- self.assertEqual为unittest提供的断言方法,判断两个参数是否相等,自动化测试的逻辑就是判断理论值和实际值是否相同,来判断用例是否通过。
  1. 在运行配置里增加一项:
    在这里插入图片描述

  2. 点击运行即可。
    如果是上例,结果为用例不通过,结果为false
    在这里插入图片描述
    如果把断言改成:

self.assertEqual(True, True)

结果就变成:
在这里插入图片描述

  • pycharm还提供了重新跑失败用例等功能。
  • unittest提供了丰富的断言功能,比如不相等,容器直接比较等,就不一一说了,有兴趣的朋友可以自己去试。

selenium

selenium现在是一套完整的框架,我使用到的就是web driver这个模块,实际上我理解就是一个爬虫引擎:

  • 获取页面
  • 解析DOM,可以通过get_element等一系列函数获取DOM中的元素
  • 事件驱动,可以对DOM上的一些组件事件进行点击。

driver现在支持多种浏览器,包括edge,firefox,chrome等。
我自己用到的是chrome。

下载web driver

下载地址:
https://chromedriver.storage.googleapis.com/index.html
找到所需浏览器的版本,版本号找一个相近的即可。

web driver的基本使用

from selenium import webdriver

driver = webdriver.Chrome(executable_path=‘d:\xxxx.exe’) # 确定driver的地址
driver.get('http://localhost:8080')  # 获取http地址
driver.maximize_window()  # 窗口最大化
driver.implicitly_wait(10) # 等待时长

上面代码中最后一句设置等待时长是很关键的,因为因为网络传输和DOM处理加载都是需要时间的,可能自动化代码执行的时候,某个DOM元素还没有被加载好,driver就会有获取不到的可能,这个数字就是表名在多少秒之内进行等待DOM完成构建。

也可以通过显式的等待来处理:
import time

driver.get(xxxx)
time.sleep(10)
driver.find_element()

driver 定位元素

selenium获取元素可以根据DOM元素的ID,name,class或者精确的XPATH来进行定位。
当然最好的方式是使用ID,但是需要在开发的时候对对应的元素进行“埋点”处理。
在selenium3的时候,定位元素是通过

element = find_element_by_id('xxx')
element = find_element_by_name('xxx')
element = find_element_by_xpath('xxx')

来实现的。

而在selenium4的时候,这几个函数整合成一个函数了:
find_element
但是还是需要通过指定参数来确认定位方式:

from selenium.webdriver.common.by import By

element = find_element(by=By.ID, value='xxx')
element = find_element(by=By.NAME, value='xxx')
element = find_element(by=By.XPATH, value='xxx')

driver使用事件

  • 文本输入
driver.find_element(by=By.XPATH, value=‘xxx’).send_keys('abcde')

# 或者
element = find_element(by=By.XPATH, value='xxx')
element.send_keys('abcde')
  • 鼠标左键
driver.find_element(by=By.XPATH, value=‘xxx’).click('abcde')

# 或者
element = find_element(by=By.XPATH, value='xxx')
element.click('abcde')
  • 鼠标右键
from selenium.webdriver.common import action_chains

element = driver.find_element(by=By.XPATH, value=‘xxx’)

ac_1 = action_chains.ActionChains(driver)
ac_1.context_click(element).perform()
  • 下拉框
    下拉框实际上就是两次点击

处理下拉框

处理下拉框实际上就是两次点击,第一次点击是下拉框组件,第二次点击是其中的内容

driver.find_element(by=By.XPATH, value='dropbox_file').click()
# 等待一下
time.sleep(3)

# 选择文本
driver.find_element(by=By.XPATH, value='dropbox_txt').click()

处理复选框

复选框上也是一个点击动作:

driver.find_element(by=By.XPATH, value='item_checkbox').click()

自动化框架的基本逻辑就是:

  • 从界面上获取相应组件的信息,然后把这些信息和数据库,分布在各个地方的文件进行比对,如果比对的上,那么就是用例通过。那么在搭建一个完整的用例系统里,就必须用到python的ssh,ftp,各种数据库的库函数。我这里用到了下面几种,我理解基本覆盖了一个web系统能用到的基本组件。
  • ssh,对应的是paramiko库
  • ftp,对应的是ftplib库
  • sqlserver,对应的是pymssql库
  • oracle,对应的是cx_oracle库
  • excel,对应的是openpyxl库
  • seaweed,对应的是pycurl库,因为seaweed对外提供了访问数据的http服务。
  • mongodb,对应的是pymongo库。

ssh

我使用的库是paramiko库:

  1. 第一步就是初始化ssh连接:
import paramiko
ssh_conn = paramiko.SSHClient()

# 设置信任远程机器,允许访问
# 设置远程服务器没有在know_hosts文件中记录时的应对策略。目前支持三种策略:
#     AutoAddPolicy 自动添加主机名及主机密钥到本地HostKeys对象,不依赖load_system_host_key的配置。即新建立ssh连接时不需要再输入yes或no进行确认
#     WarningPolicy 用于记录一个未知的主机密钥的python警告。并接受,功能上和AutoAddPolicy类似,但是会提示是新连接
#     RejectPolicy 自动拒绝未知的主机名和密钥,依赖load_system_host_key的配置。此为默认选项
ssh_conn.set_missing_host_key_policy(paramiko.AutoAddPolicy())
  1. 进行连接
try:
    # ssh
    self.ssh_conn.connect(config.ssh_ip,
                          config.ssh_port,
                          config.ssh_username,
                          config.ssh_pwd)

    # sftp,如果使用sftp协议上传的时候可以使用
    transport = paramiko.Transport(config.ssh_ip, config.ssh_port)
    # 这里一定要使用username=和password=,因为第一个参数是hostkey
    transport.connect(username=config.ssh_username, password=config.ssh_pwd)
    self.sftp_conn = paramiko.SFTPClient.from_transport(transport)

except:
    print("Failed to connect to remote server") 
  1. 通过连接对象执行shell命令,我没有用sftp,用的是ftp协议。
shell_cmd = "mv /home/x.txt /home/y.txt"
stdin, stdout, stderr = ssh_conn.exec_command(shell_cmd )
  1. 通过stdout获得执行情况
    stdout实际上是一个输出流,就是把服务器上执行shell命令的输出作为字节流输出:
print(stdout.read())

输出为:b’abc\n’

ftp

ftp使用的是ftplib库,是python自带的库。
操作和ssh类似:

  1. 初始化和连接,多了一个登录操作
from ftplib import FTP
conn = FTP()
conn.connect(config.ftp_ip, config.ftp_prot)
conn.login(config.ftp_user, config.ftp_pwd)
  1. 上传文件:
buff_size = 1024 * 1024 * 1024   # 默认大小
fp = open(local_file_path, 'rb')
try:
    conn.storbinary('STOR %s' % remote_file_path, fp, buff_size)
except Exception as e:
    print('发送文件error:{}'.format(e))

相当于是要打开本地文件,然后读取出来,以字节流的方式向远端的ftp服务器写入。

  1. 下载文件,和上传类似
# 切换到目标目录,相当于cd命令
conn.cwd(path_name)

tmp_file = open('./temp/temp.txt', 'wb')
conn.retrbinary('RETR ' + remote_file_name, tmp_file.write)
tmp_file.close()

相当于打开一个本地文件,以字节流的方式从远端把文件内容读写到本地文件中。

  1. 上传和下载文件夹,这个库中没有直接上传文件夹的api,必须自己写递归,把文件夹中的子文件夹和文件都一次上传或下载。
    下面是一个递归上传的函数,下载的类似
def upload_data_dir(self, local_file_path, remote_file_path):
files = os.listdir(local_file_path)
        if remote_file_path:
            try:
                self.conn.mkd(remote_file_path)
            except Exception as e:
                pass
            finally:
                self.conn.cwd(remote_file_path)

        for file_name in files:
            print(local_file_path + r'/{}'.format(file_name))
            if os.path.isfile(local_file_path + r'/{}'.format(file_name)):
                self.upload_file_indir(local_file_path, file_name)
            elif os.path.isdir(local_file_path + r'/{}'.format(file_name)):
                try:
                    self.conn.mkd(file_name)
                except Exception as e:
                    pass
                finally:
                    local_file_path = "%s/%s" % (local_file_path, file_name)
                    remote_file_path = "%s/%s" % (remote_file_path, file_name)

                self.upload_data_dir(local_file_path, remote_file_path)

def upload_file_indir(self, path, file_name, target_dir=None, callback=None):
    # 记录当前 ftp 路径
    cur_dir = self.conn.pwd()
    if target_dir:
        try:
            self.conn.mkd(target_dir)
        except:
            pass
        finally:
            self.conn.cwd(os.path.join(cur_dir.title(), target_dir))
    file = open(os.path.join(path, file_name), 'rb')  # file to send
    self.conn.storbinary('STOR %s' % file_name, file, callback=callback)  # send the file
    file.close()  # close file
    self.conn.cwd(cur_dir)
  1. 删除文件和文件夹
try:
    self.conn.delete(file_name)
    time.sleep(3)
except Exception as e:
    print(e)

同样的,删除文件夹也需要自己写递归,删除文件夹的命令为:

conn.rmd("%s/%s" % (remote_dir, dir_name)

如果删除的这个文件夹不为空的话,是会失败的,所以需要先递归删除文件夹中的所有内容,最后删除文件夹

  1. 最关键的一点,所有的上传,下载,删除都是一个异步操作,也就是说调用之后,ftplib库会直接返回成功,然后再去删除。所以函数执行成功之后,不一定是已经将文件上传了的。

数据库

sqlserver

sqlserver用的是pymssql库,这个库安装的时候需要安装基础的visual studio运行环境,否则会安装失败。
使用起来比较简单,我暂时只使用了查询功能。

  1. 连接:
import pymssql
self.conn = pymssql.connect(host='xxxx',  # 这里的host='_'可以用本机ip或ip+端口号
                               server="master",  # 本地服务器
                               port="1433",  # TCP端口
                               user="xx", password="xxxx",
                               database="xxxx",
                               charset="GBK"
                               # 这里设置全局的GBK,如果设置的是UTF—8需要将数据库默认的GBK转化成UTF-8
                               )
        if self.conn:
            print('连接数据库成功!')  # 测试是否连接上
        else:
            print('未连接')  # 测试是否连接上
  1. 查询:
# 查询语句
        cursor = self.conn.cursor()  # 使用cursor()方法获取操作游标
        sql_select = "SELECT * FROM " + table_name + " where colName = \'" \
                     + queryValue + "\'"   # 数据库查询语句

        cursor.execute(sql_select)  # 执行语句
        results = cursor.fetchall()  # 获取所有记录列表

        for result in results:
        	dosomething()

oracle

安装

我使用的是cx_oracle库,这个库底层是调用的oci的库,所以最好本地安装了pl-sql这样的软件。或者单独下载oracle的客户端运行环境进行安装,然后把安装目录中的一些dll(windows的开发环境)拷贝到python环境的根目录下:
在这里插入图片描述
在这里插入图片描述
我用的是anaconda工具。

使用

  1. 连接
import cx_Oracle
conn_str = f"{user}/{password}@{host}/{service_name}"  # 
self.conn = cx_Oracle.connect(conn_str)
  1. 查询
cursor = self.conn.cursor()
        sql = 'select * from ' + view_name + \
              ' where "colname" = \'' + colValue + '\''

        cursor.execute(sql)
        results = cursor.fetchall()

        for result in results:
            dosomething()

mongodb

使用的是pymongo库

  1. 连接
import pymongo

mongo_url = 'mongodb://ip:27017/'
self.conn = pymongo.MongoClient(mongo_url)
self.db = self.conn[config.mongo_db_name]
self.config_table = self.db['collectionName']
  1. 查询
dblist = self.config_table.find({'key': keyValue})
  1. 更新
self.config_table.update_one({'key': key}, {'$set': {'value': value}})

excel

使用的是openpyxl 库

from openpyxl import load_workbook

wb = load_workbook(file_name)
ws = wb.active

# I2就是单元格的索引
print(ws['I2'].value)

还有很多操作,我在用例里没有用到,就不一一介绍了,网上内容一搜一大把。

pycurl

相当于执行curl命令的库,我们系统中使用到了seaweed,seaweed提供了http服务,用于上传文件:

  1. 访问ip:port/dir/assign地址可以获得一个id
  2. 使用这个ID,通过另外一个url上传一个文件。

使用pycurl实现第一步:

def write_func_for_file_id(self, buffer):
        self.result = eval(buffer)
        self.file_id_url = 'http://' + self.result['url'] + '/' + self.result['fid']
        self.file_id = self.result['fid']
        
c = pycurl.Curl()
c.setopt(pycurl.URL, "http://ip:port/dir/assign")

## 在opt中设置pycurl.WRITEFUNCTION,需要提供一个回调函数,这个函数就负责处理http返回的response
c.setopt(pycurl.WRITEFUNCTION, write_func_for_file_id)
c.setopt(pycurl.FOLLOWLOCATION, 1)

c.perform()

pycurl实现第二步:

file = open(path)

        c = pycurl.Curl()
        c.setopt(pycurl.URL, self.file_id_url)
        # opt设置pycurl.UPLOAD
        c.setopt(pycurl.UPLOAD, 1)
        # opt设置pycurl.READDATA
        c.setopt(pycurl.READDATA, file)
        # 同样需要一个回调,但是这里我不需要处理response
        c.setopt(pycurl.WRITEFUNCTION, self.write_func_for_upload)
        c.setopt(pycurl.FOLLOWLOCATION, 1)

        c.perform()
        file.close()

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

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

相关文章

泰裤辣!Corona 10强势来袭,蓝海创意云同步更新支持

2023年6月22日,Chaos Corona官网发布了Chaos Corona 10 for 3ds Max and Cinema 4D版本。本次不仅更新了新功能,还优化了渲染卡顿的问题,一起来看看有哪些实用的好玩意吧! 1.贴花影响特定通道 CR10在你的场景中焕然一新&#xff…

Git报错: Please move or remove them before you switch branches.

Bug记录:在我写需求的时候,产品说上个包有崩溃,于是我就控制台 git checkout切分支,结果报错Please move or remove them before you switch branches.下面是被改动的文件,因为是项目build的时候产生的临时文件&#x…

在虚幻引擎中创建大气的HIMIL电影作品

今天瑞云渲染小编给大家带来了关于电影制片人Tiziano Fioriti展示了《H I M I L》项目背后的工作流程,解释了人工智能是如何用于细节的,并谈到了设置火光的问题。 介绍 大家好,我叫Tiziano Fioriti,是来自意大利的自由电影制作人…

RabbitMQ管理界面介绍

1.管理界面概览 connections: 无论生产者还是消费者,都需要与RabbitMQ建立连接后才可以完成消息的生产和消费,在这里可以查看连接情况 channels: 通道,建立连接后,会形成通道,消息的投递获取依…

高阶常系数微分方程——笔记整理

首先,介绍基本知识: 首先,我们对式子进行处理得到: 得到特征根是 和 0, 所以其通解 假设特解是,带入方程所得:

Nik Color Efex 滤镜库

Nik Color Efex 滤镜库中提供了 55 个滤镜。有关这些滤镜的详细参数说明请分别参阅: 1 ~ 11 《Nik Color Efex 滤镜详解(1/5)》 12 ~ 22 《Nik Color Efex 滤镜详解(2/5)》 23 ~ 33 《Nik Color Efex 滤镜详解&#x…

2023年java还是golang还是c#?

前言 我们可以先来看一下这三门语言各自的优劣 学习曲线:如果你是初学者或对编程相对陌生,Java可能是一个较好的选择。它有广泛的学习资源和社区支持,易于上手。Go也有简单易学的特点,但由于相对较年轻,相关的学习资…

为何收入或存款增量难找存量告急

其实,和年纪关系不太大吧,平凡的普通人都没多少存款。 *近日,有调查称“大概五分之一的年轻人存款在一万元以内。10万元存款是一个“坎”,存款超过10万就会超过53.7%的人。”“年轻人”“存款”两个词碰撞在一起,引来了…

python3中http协议提供文件服务器功能

http协议是互联网的通用基础协议,也可以利用其来开发文件服务器,给客户提供文件浏览,查看,下载,上传等功能。 目录 1.python3自带http文件服务 2.python3从头开发http文件服务 1.python3自带http文件服务 python3中…

资源调度框架 YARN

3.1.1 什么是YARN Yet Another Resource Negotiator, 另一种资源协调者通用资源管理系统为上层应用提供统一的资源管理和调度,为集群在利用率、资源统一管理和数据共享等方面带来了巨大好处 3.1.2 YARN产生背景 通用资源管理系统 Hadoop数据分布式存储&#xff08…

【打杂记录】-能否开发一个报账系统,自动批量识别与完成报账任务?

能否开发一个报账系统,自动批量识别与完成报账任务? 今天这篇博客,我想说些非技术性语言。我在研二一年负责实验室的报账工作,近期终于有机会将工作交接给下一位负责人,我的科研时间又回来了。 在这一年里&#xff0c…

centos7 挂载未分配的空间新增卷

一、系统环境 操作系统:Centos 7 已配置环境:空 二、磁盘挂载到新目录(磁盘挂载) 2.1 查找新硬盘 查看机器所挂硬盘及分区情况: fdisk -l 复制 红框圈中的即是本次要挂载的磁盘,与 /dev/sda 和 /de…

掌握多线程的用法一篇就够了

多线程 线程与进程进程线程线程调度速度问题 创建线程的方式第一种:继承Thread类原理分析 第二种:实现Runnable接口的形式第三种:有返回值的线程 Thread类的方法Thread和Runnable的区别线程安全问题举例测试代码线程安全问题分析案例解决办法分析方案一:使用同步代…

SpringSecurity基础入门详解

【1】SpringSecurity是什么 Spring 是非常流行和成功的 Java 应用开发框架,Spring Security正是Spring家族中的成员。Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案。 正如你可能知道的关于安全方面的两个主要区域是“认…

使用英特尔 oneAPI AI 工具分析包实现AI应用程序的调试与改进

目录 1.什么是英特尔 oneAPI AI? 关于英特尔 oneAPI AI 工具分析包 2.使用英特尔 oneAPI AI 工具分析包实现AI数据分析 准备工作 数据准备 编写AI应用程序 性能分析 并行性优化 内存和线程错误分析 优化AI算法 性能验证与调试 性能优化迭代 3.总结 1.什…

「2024」预备研究生mem-概率基础加法公式乘法公式古典概型基础

一、概率基础 二、加法公式 三、乘法公式&古典概型基础 均不是1点 除了不是1的概率 不全是1点:也有可能是1点, 理解为 对是1点取非 相互独立 相乘 古典概型: 从A出发,先到B, 先到D,先到C(…

记录字符串压缩

参考代码 class Solution { public:string num2str(int val){string ans;while(val/10){ans.push_back((char)(0val%10));val/10;}ans.push_back((char)(0val%10));return ans;}string compressString(string S) {string ssS;S.push_back(\n);int left0,right1;int n S.size(…

数字孪生场景渲染能力中的WebGL技术路线

使用三维建模技术构建出的虚拟现实场景后,需要通过渲染引擎实现场景的高精度、高保真和实时渲染。同时,需要将现实场景中的数据信息融合到虚拟场景中,实现对现实情况的监测和控制。 目前大多数数字孪生城市项目在三维渲染引擎的技术选型上通…

高性能哈希算法MurmurHash

参考链接: https://blog.51cto.com/u_15127622/3264772 md5算法_十分钟掌握高性能哈希算法MurmurHash_weixin_39616339的博客-CSDN博客 Murmur哈希算法 一种非加密型哈希算法,适用于一般的哈希检索操作,由Austin Appleby创建于2008年。 …

Nat.Commun.:展示了首个硅量子光源!

光子盒研究院 量子技术有望通过启用全新的通信、传感和计算方法来彻底改变社会。例如,量子密码学如果能够实现,将为抵御黑客提供无与伦比的数据安全水平:这是因为量子信息可以在光子(单个光粒子)中进行编码、无法被复制…