python+selenium+unittest+HTMLTestRunner读取csv文件参数化登陆测试

2023-11-03

之前尝试了Python+selenium+unittest+HTMLTestRunner(传送门)写了登陆脚本,然后又看了参数化及循环,于是决定写个参数化的登陆脚本。当然遇到问题是在所难免的,几经周折,最后还是完成了参数化脚本。所以写下本帖记录一下,方便以后查阅。现在先来分析一下脚本出现的问题,一开始脚本是这样的:

#构建登陆类,用unittest框架,所以是unittest.testCase
class test(unittest.TestCase):
    #构建登陆异常的方法
    def test_login(self):
        dr=webdriver.Chrome()   #调用谷歌浏览器,其他浏览器更改drvier
        #需要测试的网页
        dr.get('https://passport.cnblogs.com/user/signin')
      #构建参数化,格式为[[,,,],[,,,],[,,,]...[,,,],
      #最外面[]里的每个[]为一条用例,每条用例的项用,隔开
        user_pass=[['1','1','错误的用户名登陆','login_username_error','lblUserNameError',u'用户名错误!'],
                   ['','123456','不输入用户名登陆','login_username_null','lblUserNameError',u'请输入用户名!'],
                   ['testuser','1','错误的密码登陆','login_password_error','lblUserPwdError',u'密码错误'],
                   ['1','','不输入密码登陆','login_username_null','lblUserPwdError',u'请输入密码!']]
        #参数化定义变量,变量名自定义,数量为需要变量的数量
        #最多不超过参数化的数量,顺序与定义参数化的值顺序一致
        for (a,b,c,d,e,f) in user_pass:
            #输入用户名,定义a在最前面,所以对应用例的一个值
            #find_element_by_id里的值为网页抓取到的元素
            dr.find_element_by_id('input1').send_keys(a)
            #输入密码,b为参数化的密码
            dr.find_element_by_id('input2').send_keys(b)
            #点击登陆,click()为点击事件
            dr.find_element_by_id('signin').click()
            sleep(1)
            print (c)#c为参数化的测试目的 
            #get_screenshot_as_file为截图方法,path为路径
            #d为参数化的图片名
            dr.get_screenshot_as_file(path+d+".jpg")  
            #先验证提示类型是否正确,e为会显示错误信息的id元素
            assert dr.find_element_by_id(e).text,'提示信息类型错误!'
            #如果提示类型正确,就会有错误信息,将错误信息赋值给定义的变量
            error_message = dr.find_element_by_id(e).text
            #asserEqual()是unittest框架中的一种断言,比较两个值是否相等
            #f为参数化预期值
            self.assertEqual(error_message,f)
            #refresh()为浏览器刷新
            dr.refresh()

脚本构建在这里,基本算是完成了,当然完整脚本还要加上import包,还有HTMLTestRunner框架生成报告。但是脚本运行的时候,只运行了一次,后面的参数化没运行。当时好郁闷,查阅各种资料,尝试简单的for循环,发现语句没有出现问题,可就是只运行了一次。然后我就找参数化的原因(也怪自己,想看异常结果,所以参数化故意写错,而且还是第一个),结果一改正,哈哈哈~~脚本跑起来了,原来在for循环的时候,出现错误或者预期与实际不匹配,循环就会结束,不会跳转到下一循环。


想象这样肯定是不行的,测试就是确认和验证预期结果与实际结果的比较,一不对就停止循环,无法实现自动化测试。于是就开始调试脚本,最后想到抛出异常(抛出异常后,即使错误脚本也会默认pass),所以脚本加入try...except...


于是脚本被改成了这样(为了报告更直观,所以加了大量的print显示):

......
try:
      assert dr.find_element_by_id(e).text
      try:
           error_message = dr.find_element_by_id(e).text
           self.assertEqual(error_message,f)
           print('提示信息正确!预期值与实际值一致:')
           print('预期值:'+f)
           print('实际值:'+error_message)
      except:
           print ('提示信息错误!预期值与实际值不符:')
           print ('预期值:'+e)
           print('实际值:'+error_message)
except  
    print ('提示信息类型错误,请确认元素名称是否正确!')

脚本终于完善了,又发现之前参数化的内容,少了还好,多了维护起来就很不方便了,于是有想到了python可以读取csv文件,于是将参数文件格式改成这样:

#要读取的scv文件路径,my_file为自定义变量
my_file='C:\\Users\\Administrator\\Desktop\\login1.csv'
#csv.reader()读取csv文件,
#Python3.X用open,Python2.X用file,'r'为读取
#open(file,'r')中'r'为读取权限,w为写入,还有rb,wd等涉及到编码的读写属性
data=csv.reader(open(my_file,'r'))
#user[0]表示csv文件的第一列,user[1]表示第二列,user[N]表示第N列
新建excel文件按( A列为用户名,B列为密码,C列为测试目的,D列为截图名称,E列为各元素id名,F列为预期值)格式写入用例内容(根据实际情况修改和变化位置),另存为逗号隔开的csv文件即可:


经过几次调整,终于一份完整的脚本写好了,以下就是完整的参数化脚本:

#coing=utf-8

import csv   #导入scv库,可以读取csv文件
from selenium import webdriver
import unittest
from time import sleep
import time
import os

dr=webdriver.Chrome()

class test(unittest.TestCase):
    def test_login(self):
        '''登陆测试'''
        #要读取的scv文件路径
        my_file='C:\\Users\\Administrator\\Desktop\\login1.csv'
        #csv.reader()读取csv文件,
        #Python3.X用open,Python2.X用file,'r'为读取
        #open(file,'r')中'r'为读取权限,w为写入,还有rb,wd等涉及到编码的读写属性
        data=csv.reader(open(my_file,'r'))
        #for循环将读取到的csv文件的内容一行行循环,这里定义了user变量(可自定义)
        #user[0]表示csv文件的第一列,user[1]表示第二列,user[N]表示第N列
        #for循环有个缺点,就是一旦遇到错误,循环就停止,所以用try,except保证循环执行完
        for user in data:
            dr.get('https://passport.cnblogs.com/user/signin')
            #dr.find_element_by_id('input1').clear()
            dr.find_element_by_id('input1').send_keys(user[0])
            #dr.find_element_by_id('input2').clear()
            dr.find_element_by_id('input2').send_keys(user[1])
            dr.find_element_by_id('signin').click()
            sleep(1)
            print ('\n'+'测试项:'+user[2])
            dr.get_screenshot_as_file(path+user[3]+".jpg")
            try:
                assert dr.find_element_by_id(user[4]).text
                try:
                    error_message = dr.find_element_by_id(user[4]).text
                    self.assertEqual(error_message,user[5])
                    print('提示信息正确!预期值与实际值一致:')
                    print('预期值:'+user[5])
                    print('实际值:'+error_message)
                except:
                    print ('提示信息错误!预期值与实际值不符:')
                    print ('预期值:'+user[5])
                    print('实际值:'+error_message)
            except:
                print ('提示信息类型错误,请确认元素名称是否正确!')
                
    def tearDown(self):
        dr.refresh()

if __name__=='__main__':
        #导入HTMLTestRunner库,这句也可以放在脚本开头
    from HTMLTestRunner import HTMLTestRunner

    #定义脚本标题,加u为了防止中文乱码
    report_title = u'登陆模块测试报告'

    #定义脚本内容,加u为了防止中文乱码
    desc = u'登陆模块测试报告详情:'
    
    #定义date为日期,time为时间
    date=time.strftime("%Y%m%d")
    time=time.strftime("%Y%m%d%H%M%S")

    #定义path为文件路径,目录级别,可根据实际情况自定义修改
    path= 'D:/Python_test/'+ date +"/login/"+time+"/"

    #定义报告文件路径和名字,路径为前面定义的path,名字为report(可自定义),格式为.html
    report_path = path+"report.html"
    
    #判断是否定义的路径目录存在,不能存在则创建
    if not os.path.exists(path):
        os.makedirs(path)
    else:
        pass

    #定义一个测试容器
    testsuite = unittest.TestSuite()
    
    #将测试用例添加到容器
    testsuite.addTest(test("test_login"))
    
    #将运行结果保存到report,名字为定义的路径和文件名,运行脚本
    with open(report_path, 'wb') as report:
        runner = HTMLTestRunner(stream=report, title=report_title, description=desc)
        runner.run(testsuite)

    #关闭report,脚本结束
    report.close()
    #关闭浏览器
    dr.quit()


效果图(还是很一目了然的~哈哈哈哈~~~):


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

python+selenium+unittest+HTMLTestRunner读取csv文件参数化登陆测试 的相关文章

随机推荐

  • AJAX分页以及IFRAME载入

    AJAX获取数据并分页显示 ul class movList ul div div
  • leetcode-03. 数组中重复的数字刷题笔记(c++)

    写在前面 难度 简单 unordered map 或 sort排序 大数组方法异常溢出 数据量 小数据量 数组元素作为下标 大数据量 无需map映射 耗费空间 sort排序 前后元素是否等值 题目详情 找出数组中重复的数字 在一个长度为 n
  • 一条慢SQL引发的改造

    前言 闲鱼服务端在做数据库查询时 对每一条SQL都需要仔细优化 尽可能使延时更低 带给用户更好的体验 但是在生产中偶尔会有一些情况怎么优化都无法满足业务场景 本文通过对一条慢SQL的真实改造 介绍解决复杂查询的一种思路 以及如何使得一条平均
  • Seata 处理分布式事务

    文章目录 1 Seata 简介2 2 Seata的安装 2 1 修改配置文件 2 2 在nacos上创建配置文件 seataServer yaml 2 3 安装路径seata seata server 1 6 0 seata script
  • C# —— 面向对象编程练习

    C 面向对象编程练习 基础题 代码如下 class Program static void Main string args rectangle r new rectangle Console WriteLine 调用不含参构造函数初始化后
  • [ElasticSearch]painless脚本获取字段方式及性能比较

    一 3种常见方式 doc fieldname 常用于在搜索或排序等无状态操作时进行使用 params source fieldname 也是常用在搜索或排序中 但更多用在获取额外字段时灵活操作时使用 如不获取某个字段直接使用params s
  • 基于图像形态学处理和边缘提取算法的路面裂痕检测matlab仿真

    目录 1 算法运行效果图预览 2 算法运行软件版本 3 部分核心程序 4 算法理论概述 5 算法完整程序工程 1 算法运行效果图预览 2 算法运行软件版本 matlab2022a 3 部分核心程序 Rr Cc size Image1 获取
  • 适配器模式(Adapter)

    适配器是一种结构型设计模式 它能使接口不兼容的对象能够相互合作 又称封装器模式 Wrapper 适配器模式通过封装对象将复杂的转换过程隐藏于幕后 被封装的对象甚至察觉不到适配器的存在 例如 你可以使用一个将所有数据转换为英制单位 如英尺和英
  • C#中的解构

    解构是将一个对象分割成若干部分并将其存储到新的变量中 在 C 中 解构可以方便地一次性将一个对象的多个成员的值存储到多个变量中 1解构元组 元组为方法返回多个值提供了便捷 无需创建额外的类型来承载返回的值 例如 下面这个方法使用元组返回两个
  • 创建进程函数fork的使用(Linux系统编程)

    使用fork函数创建一个进程 pid t fork void fork函数调用成功 返回两次 返回值为0 代表当前进程是子进程 返回值为非负数 代表当前进程为父进程 如果调用失败则返回 1 代码 include
  • 肝进ICU,万字真言点化八大排序——我奶奶都看得懂的算法详解

    目录 传统艺能 排序应用 插入排序 冒泡排序 希尔排序 预排序 堆排序 选择排序 快速排序 hoare 法 挖坑法 前后指针法 取中优化 小区间优化 非递归快排 归并排序 非递归归并 各类算法复杂度比较 传统艺能 小编是双非本科大一菜鸟不赘
  • linux内核——list_for_each_entry

    在Linux内核源码中 经常要对链表进行操作 其中一个很重要的宏是list for each entry 意思大体如下 假设只有两个结点 则第一个member代表head list for each entry的作用就是循环遍历每一个pos
  • linux 文件的压缩、打包与备份

    1 gzip 可以说是应用最广的压缩命令了 可以解开 compress zip gzip 等软件所压缩的文件 gzip所创建的压缩文件为 gz 的文件名 gzip 和 bzip2 用法几乎相同 2 最常见的打包命令tar c 建立压缩档案
  • 步道乐跑怎么刷次数_团团提醒您,您的步道乐跑次数不足,请及时充值哦

    你干嘛去 跑步去啊 等等我 我们一起 不知道那大明湖畔的步道乐跑大家还记得吗 步道乐跑被许多人戏称为 立志于摧残锻炼大学生的App 在学期刚开始的时候 大家也是立过flag 想要自律 每天两公里 争取早日跑完乐跑 相信你们在前几天是这样的
  • SpringBoot连接mysql密码正确但SQLException: Access denied for user ‘root‘@‘localhost‘ (using password: YES)

    SpringBoot mysql连接问题简介 在application yml文件中设置datasource配置如下 此时不加双引号 执行数据库连接 会出现异常java sql SQLException Access denied for
  • 产品经理不懂技术的后果很严重

    目前产品研发的流程中分工越来越细 很多公司都将产品和研发进行了分离 产品负责需求的分析和产品的设计 很多产品并不懂技术 而且由于这种分离很多时候都是用跨部门来设定的 因此产品和技术的沟通很难 这就导致了以下普遍存在的问题 1 系统的扩展性非
  • MySQL用户权限及管理

    一 mysql创建用户 1 创建用户 mysql gt create user test identified by 123456 创建了用户 但是没有任何权限 Query OK 0 rows affected 0 00 sec mysql
  • JAVA线程同步

    线程同步 线程同步 即当有一个线程在对内存进行操作时 其他线程都不可以对这个内存地址进行操作 直到该线程完成操作 其他线程才能对该内存地址进行操作 而其他线程又处于等待状态 实现线程同步的方法有很多 为什么要创建多线程 在一般情况下 创建一
  • Python3实现一个简单的接口服务实现跨域请求

    使用Python实现一个简单的接口服务 可以通过get post方法请求该接口 拿到响应数据 创建一个api server py文件 添加代码如下 import json from flask import request Flask im
  • python+selenium+unittest+HTMLTestRunner读取csv文件参数化登陆测试

    之前尝试了Python selenium unittest HTMLTestRunner 传送门 写了登陆脚本 然后又看了参数化及循环 于是决定写个参数化的登陆脚本 当然遇到问题是在所难免的 几经周折 最后还是完成了参数化脚本 所以写下本帖