Unittest框架,理论和实操双管齐下(中)

发表于:2023-9-26 09:28

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:程序员小濠    来源:知乎

  七、数据驱动(unittest ddt)☆
  ddt:data-driver tests
  数据驱动:是以数据来驱动整个测试用例的执行, 也就是测试数据决定测试结果
  数据驱动解决的问题是:
  1)、代码和数据分离,避免代码冗余
  2)、不写重复的代码逻辑;
  在python解释器中需要安装 ddt 这个包才能用:
  要检查是否安装上,在cmd当中 输入 pip list命名,有ddt说明安装成功。
  语法:
  1、使用数据驱动,要在class前加上修饰器 @ddt
  说明:方法里面使用 print ,为了方便,模拟测试用例,主要是为了学习数据驱动,实际中方法里面写的是测试用例的代码:
  import unittest
  from ddt import ddt, data
  @ddt  
  class TestDemo(unittest.TestCase):
      # 单一参数
      @data('17611110000', '17611112222')
      def test_1(self, phone):
          print('测试一电话号码:', phone)
          
  if __name__ == '__main__':
      unittest.main()
  else:
      pass
  1)、结合 selenium 使用 ddt
  """
  unittest + selenium
  """
  import unittest
  from time import sleep
  from ddt import ddt, data
  from selenium import webdriver
  @ddt
  class TestBaidu(unittest.TestCase):
      def setUp(self) -> None:
          self.driver = webdriver.Chrome()
          self.driver.get('https://www.sogou.com/')
      def tearDown(self) -> None:
          sleep(3)
          self.driver.quit()
    
      # 单一参数
      @data('易烊千玺', '王嘉尔')
      def test_01(self, name):
          self.driver.find_element_by_id('query').send_keys(name)
          self.driver.find_element_by_id('stb').click()
  if __name__ == '__main__':
      unittest.main()
  self:相当于java中的this,当前对象的引用,self.driver定义了driver这个变量。
  2、在实际中不可能是单一参数进行传参,将会使用多个参数进行传参:
  注意事项:
  1)、多个数据传参的时候@data里面是要用列表形式
  2)、会用到 @unpack 装饰器 进行拆包,把对应的内容传入对应的参数;
  import unittest
  from ddt import ddt, data, unpack
  @ddt
  class TestDemo(unittest.TestCase):
      # 多参数数据驱动
      @data(['admin', '123456'])
      # unpack 是进行拆包,不然会把列表里面的数据全部传到username这个一个参数,我们要实现列表中的两个数据分别传入对应的变量中
      @unpack
      def test_2(self, username, password):
          print('测试二:', username, password)
  if __name__ == '__main__':
      unittest.main()
  else:
      pass
  但是以上步骤都是数据在代码当中的,假如要测试n个手机号这样的数据,全部写在 @data 装饰器里面就很麻烦,这就引出了数据驱动里面的代码和数据的分离。
  3、将数据放入一个文本文件中,从文件读取数据, 如JSON、 excel、 xml、 txt等格式文件 ,这里演示的是json文件类型。
  json文件处理, 这个链接介绍了json文件和Python文件基本操作
  (1)、在json文件驱动
  [
    {
      "username": "admin",
      "password": "123456"
    },
    {
      "username": "normal",
      "password": "45678"
    }
  ]
  (2)、在测试代码中读取json文件
  import json
  import unittest
  from ddt import ddt, data, unpack
  # 用json多个参数读取
  def reads_phone():
      with open('user.json', encoding='utf-8') as f:
          result = json.load(f)  # 列表
          return result
      
  @ddt
  class TestDemo(unittest.TestCase):
      # 多参数数据驱动
      @data(*reads_phone())
      # unpack 是进行拆包,不然会把列表里面的数据全部传到username这个一个参数,我们要实现列表中的两个数据分别传入对应的变量中
      @unpack
      def test_2(self, username, password):
          print('测试二:', username, password)
  if __name__ == '__main__':
      unittest.main()
  else:
      pass
  注意事项:
  1、with open里面默认是 ”r“ 
  2、@data 里面的 * 含义是实现每个json对象单个传入方法执行,不然会吧json文件里面所用数据全部传入 
    > * 是元祖;
    > ** 是字典;
  3、参数不能传错,要对应
  执行结果:
  (3)、txt文件驱动
  一行表示一组:
  admin,123456
  normal,456789
  import unittest
  def read():
      lis = []
      with open('readtext.txt', 'r', encoding='utf-8') as f:
          for line in f.readlines():
              # lis.append(line) #  ['admin,123456\n', 'normal,456789\n']
              # lis.append(line.strip('\n'))  ['admin,123456', 'normal,456789'] 两个字符串
              lis.append(line.strip('\n').split(','))  # [['admin', '123456'], ['normal', '456789']]
      return lis
  class TestDome(unittest.TestCase):
      def test_01(self):
          li = read()
          print(li)
  if __name__ == '__main__':
      unittest.main()
  """
  split():一个字符串里面用某个字符分割,返回列表
  strip():去掉两边的字符或者字符串,默认删除空白符(包括'\n', '\r',  '\t',  ' ')
  """
  (4)、csv 文件驱动
  供应商名称,联系人,移动电话
  英业达,张三,13261231234
  阿里巴巴,李四,13261231231
  日立公司,王五,13261231233
  写法一:
  """
  编写 csvv.py脚本读取csv中的测试数据
  """
  import csv
  class ReadCsv():
      def read_csv(self):
          lis = []
          # 用csv的API的reader方法!!!!
          data = csv.reader(open('testdata.csv', 'r'))  #!!!!
          next(data, None)
          for line in data:
              lis.append(line)
              # lis.append(line[0])  # 二维数组可以省略行,列不可以省略
              # lis.append(line[1])
          return lis
  # 实例化类
  readCsv = ReadCsv()
  # 打印类中的方法
  print(readCsv.read_csv())
  写法二:推荐
  def csvTest():
      li = []
      with open('user.csv', 'r', encoding='utf-8') as f:
          filename = csv.reader(f)
          next(filename, None)
          for r in filename:
              li.append(r)
          return li
  (5) 、yaml文件驱动
  -
    username: admin9
    password: 123456
  -
    username: normal
    password: 789456
  对应的json文件
  [
    {
      "username": "admin9",
      "password": 123456
    },
    {
      "username": "normal",
      "password": 7894
    }
  ]
  写法:
  """
  使用yaml数据驱动
  """
  import unittest
  from time import sleep
  from selenium import webdriver
  from ddt import ddt, data, unpack, file_data
  @ddt
  class YamlTest(unittest.TestCase):
      def setUp(self) -> None:
          self.driver = webdriver.Chrome()
          self.driver.get('file:///D:/%E6%A1%8C%E9%9D%A2/page/%E6%B3%A8%E5%86%8CA.html')
          self.driver.maximize_window()
      def tearDown(self) -> None:
          driver = self.driver
          sleep(3)
          driver.quit()
      # file_data 传入多个参数的时候,@unpack 的解包不起作用
      @unittest.skip
      @file_data('../user.yaml')
      @unpack
      def test_yaml01(self, username, password):
          driver = self.driver
          driver.find_element_by_id('userA').send_keys(username)
          driver.find_element_by_id('passwordA').send_keys(password)
      # 注意:传的参数名称要与yaml文件对应
      # 在yaml数据中文件中采用对象(键值对)的方式来定义数据内容
      @file_data('../user1.yaml')
      def test_yaml02(self, username, password):
          driver = self.driver
          driver.find_element_by_id('userA').send_keys(username)
          driver.find_element_by_id('passwordA').send_keys(password)
  if __name__ == '__main__':
      unittest.main()
  注意:file_date 装饰器,可以直接读取yaml和json文件
  (5)、Excel文件驱动
  建立excel表的时候需要退出pychram在根目录下创建excel表保存,否则会报错
  def read_excel():
      xlsx = openpyxl.load_workbook("../excel.xlsx")
      sheet1 = xlsx['Sheet1']
      print(sheet1.max_row)  # 行
      print(sheet1.max_column)  # 列
      print('=======================================================')
      allList = []
      for row in range(2, sheet1.max_row + 1):
          rowlist = []
          for column in range(1, sheet1.max_column + 1):
              rowlist.append(sheet1.cell(row, column).value)
          allList.append(rowlist)
      return allList
  用excel登录csdn操作:
  """
  测试excel数据驱动
  """
  import unittest
  from time import sleep
  import openpyxl as openpyxl
  from ddt import ddt, data, unpack
  from selenium import webdriver
  # 读取excel表中的数据,使用xlrd,openpyxl
  def read_excel():
      xlsx = openpyxl.load_workbook("../excel.xlsx")
      sheet1 = xlsx['Sheet1']
      print(sheet1.max_row)  # 行
      print(sheet1.max_column)  # 列
      print('=======================================================')
      allList = []
      for row in range(2, sheet1.max_row + 1):
          rowlist = []
          for column in range(1, sheet1.max_column + 1):
              rowlist.append(sheet1.cell(row, column).value)
          allList.append(rowlist)
      return allList
  @ddt
  class ExcelText(unittest.TestCase):
      def setUp(self) -> None:
          self.driver = webdriver.Chrome()
          self.driver.get('https://passport.csdn.net/login?code=applets')
          self.driver.maximize_window()
      def tearDown(self) -> None:
          driver = self.driver
          sleep(3)
          driver.quit()
      @data(*read_excel())
      @unpack
      def test_excel01(self, flag, username, password):
          print(flag, username, password)
          driver = self.driver
          sleep(2)
          driver.find_element_by_xpath('/html/body/div[2]/div/div[2]/div[2]/div[1]/div/div[1]/span[4]').click()
          driver.find_element_by_xpath('/html/body/div[2]/div/div[2]/div[2]/div[1]/div/div[2]/div/div[1]/div/input').send_keys(username)
          driver.find_element_by_xpath('/html/body/div[2]/div/div[2]/div[2]/div[1]/div/div[2]/div/div[2]/div/input').send_keys(password)
          driver.find_element_by_xpath('/html/body/div[2]/div/div[2]/div[2]/div[1]/div/div[2]/div/div[4]/button').click()
  if __name__ == '__main__':
      unittest.main()
  本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号