• 自动化测试模型(数据参数化方法)以及简单的文件读取方式


    一、自动化测试模型

      1.线性测试

      录制或编写对应应用程序操作步骤产生,每个线性脚本相互独立,相互之间不依赖,不调用彼此,即单纯地模拟用户完整操作场景。不易维护。

      2.模块化与类库

      将重复的操作单独封装成公共模块。在测试用例执行过程中,当需要用到模块封装时对其进行调用,如此一来便最大限度的消除了重复,从而提高测试用例的可维护性。

      3.数据驱动测试

      定义:数据的改变驱动自动化测试的执行,最终引起测试结果的改变。简单理解就是把数据驱动所需要的测试数据参数化,可以用多种方式来存储和管理这些参数化的数据(txt,html,csv,xml,json)

      4.关键字驱动测试

      又被称为【表驱动测试】或【基于动作字测试】。这类框架会把自动化操作封装为“关键字”,避免测试人员直接接触代码,多以“填表格”的形式降低脚本的编写难度。

      Robot Framework是主流的关键字驱动测试框架之一,通过它自带的Robot Framework RIDE编写。

    二、模块化与参数化

    1.简单的一个文件线性测试

      一般需要配合使用,即在创建函数或类方法时为它们设置入参,使其可以根据不同的参数执行相应的操作,下面以一个简单的126邮箱登录为例:

     1 from selenium import webdriver
     2 from time import sleep
     3 
     4 driver = webdriver.Chrome()
     5 driver.maximize_window()
     6 driver.get("http://www.126.com")
     7 # 登录
     8 sleep(5)
     9 
    10 login = driver.find_element_by_xpath("/html/body/div[2]/div[3]/div/div[3]/div[3]/div[4]/a[1]")
    11 login.click()
    12 driver.switch_to.frame(0)
    13 """
    14 (driver.find_element_by_xpath("/html/body/div[2]/div[3]/div/div[3]/div[4]/div[1]/div/iframe"))
    15 """
    16 sleep(3)
    17 user = driver.find_element_by_name("email")
    18 user.clear()
    19 user.send_keys("zudangli")
    20 driver.find_element_by_name("password").clear()
    21 driver.find_element_by_name("password").send_keys("19820818kai")
    22 driver.find_element_by_id("dologin").click()
    23 # 登录之后的动作
    24 sleep(3)
    25 # 退出
    26 driver.find_element_by_link_text("退出").click()
    27 driver.quit()

    <这里涉及到一个表单切换的问题,因为打开这个邮箱的网址后主页面显示的是扫码登录,要切换到账户密码登录的表单下,但是在尝试了多种定位iframe的方式之后(name、css_selector、xpath),切换是切换成功无疑了,因为可以找到该iframe下的元素,但就是不能执行操作,报错:(selenium.common.exceptions.ElementNotInteractableException: Message: element not interactable),也搜了很多办法,最终也无疾而终,最后只能在切换表单之前手动切换到账号登录的iframe下,暂时先这样解决吧,随着后面进一步的学习再回来看看是怎么费事!!!>

    2.将重复的动作模块化

    好了,言归正传,继续来康康如何一步步模块化……要实现邮箱的自动化登录测试项目,那每条测试用例都需要有登录动作和退出动作,此时,需要创建一个新的module.py文件存放登录和退出动作。

     1 from time import sleep
     2 
     3 
     4 class Mail:
     5 
     6     def __init__(self, driver):
     7         self.driver = driver
     8 
     9     def login(self):
    10         login = self.driver.find_element_by_xpath("/html/body/div[2]/div[3]/div/div[3]/div[3]/div[4]/a[1]")
    11         login.click()
    12         self.driver.switch_to.frame(0)
    13 14         sleep(3)
    15         user = self.driver.find_element_by_name("email")
    16         user.clear()
    17         user.send_keys("zudangli")
    18         self.driver.find_element_by_name("password").clear()
    19         self.driver.find_element_by_name("password").send_keys("19820818kai")
    20         self.driver.find_element_by_id("dologin").click()
    21 
    22     def logout(self):
    23         self.driver.find_element_by_link_text("退出").click()

      首先创建一个Mail类,在__init__()初始化方法中接收driver驱动并赋值给self.driver,在login()和logout()方法中分别使用self.driver实现邮箱的登录和退出动作,接下来修改test_mail.py测试调用Mail类中的这两个方法:

     1 from selenium import webdriver
     2 from time import sleep
     3 
     4 from files.module import Mail
     5 
     6 driver = webdriver.Chrome()
     7 driver.maximize_window()
     8 driver.get("http://www.126.com")
     9 sleep(5)
    10 # 调用Mail类并接受driver驱动
    11 mail = Mail(driver)
    12 # 登录
    13 mail.login()
    14 sleep(5)
    15 # 退出
    16 mail.logout()
    17 driver.quit()

    3.将模块中的方法参数化

      接着再进一步,如果需求是测试登录功能,虽然测试步骤是固定的,但是测试数据(账号)不同,这时就需要把login()方法参数化。修改的module.py文件代码如下:

     1 from time import sleep
     2 
     3 
     4 class Mail:
     5 
     6     def __init__(self, driver):
     7         self.driver = driver
     8         login = self.driver.find_element_by_xpath("/html/body/div[2]/div[3]/div/div[3]/div[3]/div[4]/a[1]")
     9         login.click()
    10         self.driver.switch_to.frame(0)
    11         sleep(3)
    12 
    13     def login(self, username, password):
    14         sleep(2)
    15         self.driver.find_element_by_name("email").clear()
    16         self.driver.find_element_by_name("email").send_keys(username)
    17         self.driver.find_element_by_name("password").clear()
    18         self.driver.find_element_by_name("password").send_keys(password)
    19         self.driver.find_element_by_id("dologin").click()
    20         sleep(3)
    21 
    22     def logout(self):
    23         self.driver.find_element_by_link_text("退出").click()

    (这里对Mail类中的初始化方法做了微调,由于考虑到各种测试案例下,只需要一次定位到iframe就将iframe的定位操作放到了初始化方法中)

    这样就进一步提高了login()方法的可复用性,不再使用一个固定的账号登录,而是根据被调用者传来的用户名和密码执行登录操作,相应的修改测试用例test_mail.py文件:

     1 driver = webdriver.Chrome()
     2 driver.maximize_window()
     3 driver.get("http://www.126.com")
     4 sleep(5)
     5 # 调用Mail类并接受driver驱动
     6 mail = Mail(driver)
     7 # 登录账号为空
     8 mail.login("", "")
     9 
    10 # 用户名为空
    11 mail.login("", "19820818kai")
    12 
    13 # 密码为空
    14 mail.login("zudangli", "")
    15 
    16 # 用户名密码错误
    17 mail.login("error", "error")
    18 
    19 # 正确的账号登录
    20 mail.login("zudangli", "19820818kai")
    21 mail.login("pegawayatstudying", "19970507zudangli")
    22 # ……

    4.读取数据文件

    • txt文件

    Python提供了一下几种读取txt问价的方法:

    1. read():读取整个文件
    2. readline():读取一行数据
    3. readlines():读取所有行的数据

    test.txt文件如下:

    :19820818kai
    zudangli:
    error:error
    zudangli:19820818kai
    pegawayatstudying:19970507zudangli

     创建read_txt.py文件,用于读取txt文件

     1 # 读取文件
     2 with(open("./test.txt", "r")) as user_file:
     3     data = user_file.readlines()
     4 
     5 # 格式化处理
     6 users = []
     7 for line in data:
     8     user = line[:-1].split(":")
     9     users.append(user)
    10 
    11 # 打印users二维数组
    12 print(users)

     首先通过open()以读(“r”)的方式打开test.txt文件,readlines()可读取文件中的所有行并赋值给变量data。接下来循环data中的每一行数据,[:-1]可对字符串进行切片,以省略最后一个字符,因为读取的每一行数据结尾都有一个换行符“ ”。spilt()通过冒号(:)对每行数据进行拆分,会得到数组['','19820818kai'],最后使用append()把每一组用户名和密码追加到users数组中。取users数组中的数据,得到的数组用不同的用户名/密码进行登录,代码如下:

     1 from selenium import webdriver
     2 from time import sleep
     3 from files.module import Mail
     4 from files.read_txt import users
     5 
     6 driver = webdriver.Chrome()
     7 driver.maximize_window()
     8 driver.get("http://www.126.com")
     9 sleep(5)
    10 # 调用Mail类并接受driver驱动
    11 mail = Mail(driver)
    12 # 登录账号为空
    13 mail.login(users[0][0], users[0][1])
    14 
    15 # 用户名为空
    16 mail.login(users[1][0], users[1][1])
    17 
    18 # 密码为空
    19 mail.login(users[2][0], users[2][1])
    20 
    21 # 用户名密码错误
    22 mail.login(users[3][0], users[3][1])
    23 
    24 # 正确的账号登录
    25 mail.login(users[4][0], users[4][1])
    26 mail.login(users[5][0], users[5][1])
    27 # ……

    • CSV文件

    注:可以把WPS表格或Excel表格通过文件另存为CSV类型的文件,但不要直接修改文件的后缀名来创建CSV文件,因为这样的文件并非真正的CSV文件。这里遇到一个问题:UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd3 in position 0: invalid continuation byte。解决办法:https://blog.csdn.net/moledyzhang/article/details/78978312简单来说就是用记事本打开该文件,另存为时编码格式选择UTF-8即可

     1 import codecs
     2 import csv
     3 from itertools import islice
     4 
     5 # 读取本地CSV文件
     6 data = csv.reader(codecs.open('./csv.csv', 'r', 'utf_8_sig'))
     7 # 存放用户数据
     8 users = []
     9 # 循环输出每行信息
    10 for line in islice(data, 1, None):
    11     users.append(line)
    12 # 打印
    13 print(users)

     通过Python读取CSV文件比较简单,但会遇到两个问题:

    1.中文乱码问题。codecs是Python标准的模块编码和解码器。首先通过codecs提供的open()方法,在打开文件时可以指定编码类型,如utf_8_sig,然后导入CSV模块,通过reader()方法读取文件,即可避免中文乱码问题。

    2.跳过CSV文件的首行。因为一般会在第一行定义测试字段的名字,所以在读取数据时要跳过。Python的内建模块itertools提供了用于操作迭代对象的函数,即islice()函数,可以返回一个迭代器第一个参数指定迭代对象,第二个参数指定开始迭代的位置,第三个参数表示结束位。

    • XML文件

    当需要读取的数据是不规则时,可以用XML文件。比如需要用一个配置文件来配置当前自动化测试平台、浏览器、URL、登录的用户名和密码等,这时就需要使用XML文件存放这些数据。其特点是数据保存在标签对之间,或者是作为标签的属性存放。

     1 <?xml version="1.0" encoding="utf-8" ?>
     2 <info>
     3     <platforms>
     4         <platform>Windows</platform>
     5         <platform>Linux</platform>
     6         <platform>macOS</platform>
     7     </platforms>
     8     <browsers>
     9         <browser>Firefox</browser>
    10         <browser>Chrome</browser>
    11         <browser>Edge</browser>
    12     </browsers>
    13     <url>http:www.xxxx.com</url>
    14         <login username="admin" password="123456"/>
    15         <login username="guest" password="654321"/>
    16 </info>
     1 from xml.dom.minidom import parse
     2 # 打开XML文件
     3 dom = parse('./config.xml')
     4 # 得到文档元素对象
     5 root = dom.documentElement
     6 # 获取一组标签
     7 tag_name = root.getElementsByTagName('platform')
     8 
     9 print(tag_name[0].firstChild.data)
    10 print(tag_name[1].firstChild.data)
    11 print(tag_name[2].firstChild.data)

     Python自带读取XML文件的模块,通过parse()方法可读取XML文件。documentElement()方法用于获取文档元素对象,getElementsByTagName()方法用于获取文件中的标签。这里不需要指定标签的层级关系,即获取的标签可以是任意层级的。接下来,获取标签数组中的某个元素。firstChild属性可返回被选节点的第一个子节点,data表示获取该节点的数据,它和WebDriver中的text语句作用相似。上面的代码是来获取标签对之间的数据,下面来看看如何获取标签的属性值:

     1 from xml.dom.minidom import parse
     2 dom = parse('./config.xml')
     3 root = dom.documentElement
     4 login_info = root.getElementsByTagName('login')
     5 # 获得login标签的username属性值
     6 username = login_info[0].getAttribute("username")
     7 print(username)
     8 # 获得login标签的password属性值
     9 password = login_info[0].getAttribute("password")
    10 print(password)
    11 
    12 # 获得第二个login标签的username属性值
    13 username = login_info[1].getAttribute("username")
    14 print(username)
    15 # 获得第二个login标签的password属性值
    16 password = login_info[1].getAttribute("password")
    17 print(password)

     这里主要使用getAttribute()方法获取元素的属性值,它和WebDriver中的get_attribute()方法作用相似

    • JSON文件

    JSON是一种轻量级的数据交换格式,层次结构清晰,创建user_info.json文件:

    1 [
    2   {"username": "", "password": ""},
    3   {"username": "", "password": "123"},
    4   {"username": "user", "password": ""},
    5   {"username": "error", "password": "error"},
    6   {"username": "admin", "password": "admin123"}
    7 ]

    创建read_json.py文件:

    1 import json
    2 
    3 with open("./user_info.json", "r") as f:
    4     data = f.read()
    5 
    6 user_list = json.loads(data)
    7 print(user_list)

     通过open()方法可读取user_info.json文件。因为测试数据本身是以列表和字典格式存放的,所以读取整个文件内容后,通过JSON提供的表将str类型转换为list类型即可。

  • 相关阅读:
    Vue框架构造
    JavaScript-改变this指向
    前端发展史
    python篇第10天【For 循环语句】
    python篇第10天【While 循环语句】
    python篇第8天【运算符】
    python篇第6天【数据类型】
    python篇第5天【变量】
    Python篇函数总结【输出函数】
    python篇第3天【编码规范】
  • 原文地址:https://www.cnblogs.com/pegawayatstudying/p/12166879.html
Copyright © 2020-2023  润新知