Selenium Web自动化测试框架实践

news2024/11/25 10:12:07

目录

       前言:

  项目背景

  功能实现

  项目架构

  浏览器driver定义

  用例运行前后的环境准备工作

  工具方法模块

  Pageobject页面对象封装

  执行测试用例  


       前言:

         Selenium是一个基于Web的自动化测试框架,可以通过模拟用户在浏览器上的操作,来自动化地测试Web应用程序。

  项目背景

  https://passport.csdn.net/login CSDN登录页面

  功能实现

  ·自动运行用例

  ·自动生成测试报告

  ·自动断言与截图

  ·自动将最新测试报告发送到指定邮箱

  ·数据,页面元素分离

  ·PageObject+Unittest+ddt数据驱动用例

  ·执行日志、分布式执行

  项目架构

  浏览器driver定义

from common.readFile import ReadFile
  from common.logger import Logger
  from selenium import webdriver
  logger = Logger()
  from selenium.webdriver import Remote
  class Browser():
      def __init__(self):
          config = ReadFile()
          self.browser = config.readConfig("Browser", "browser")
          self.host = config.readConfig("host","host")
          logger.info("You had select {} host {} browser.".format(self.host,self.browser))
      def driver(self):
          """
          启动浏览器驱动
          :return: 返回浏览器驱动URL
          """
          try:
              # driver = webdriver.Chrome()
              driver = Remote(command_executor='http://' + self.host + '/wd/hub',
                              desired_capabilities={ 'platform': 'ANY',
                                                     'browserName': self.browser,
                                                     'version': "",
                                                     'javascriptEnabled': True
                                                  }
                              )
              return driver
          except Exception as msg:
              print("驱动异常-> {0}".format(msg))

  用例运行前后的环境准备工作

import unittest
  from common.driver import Browser
  class StartEnd(unittest.TestCase):
      def setUp(self):
          self.driver = Browser().driver()
          self.driver.implicitly_wait(10)
          self.driver.maximize_window()
      def tearDown(self):
          self.driver.quit()

  工具方法模块

  主要封装一些公共的方法如:截图,查找最新报告:

import time
  from selenium import webdriver
  import os,sys
  sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
  from config import setting
  def inser_img(driver):
      # 指定截图存放的根目录路径
      screen_dir = setting.TEST_REPORT + '/imges/'
      rq = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
      screen_name = screen_dir + rq + '.png'
      driver.get_screenshot_as_file(screen_name)
      print('screenshot:' + screen_name)
  #查找最新的测试报告
  def latest_report(report_dir):
      lists = os.listdir(report_dir)
      lists.sort(key=lambda fn: os.path.getatime(report_dir + '\\' + fn))
      file = os.path.join(report_dir, lists[-1])
      return file
  def latest_report_img(report_dir):
      lists = os.listdir(report_dir)
      lists.sort(key=lambda fn: os.path.getatime(report_dir + '\\' + fn))
      file = os.path.join(report_dir, lists[-1])
      return file

  Pageobject页面对象封装

  基础页面类

import time
  from selenium import webdriver
  from selenium.common.exceptions import NoSuchElementException
  from common.logger import Logger
  from common.readFile import ReadFile
  logger = Logger()
  class BasePage():
      "定义一个页面基类,让所有页面都继承这个类,封装一些常用的页面操作方法到这个类"
      def __init__(self, driver):
          self.driver = driver
          config = ReadFile()
          self.baseurl = config.readConfig("BaseUrl", "url")
      def open_url(self, url):
          self.driver.get(self.baseurl + url)
      # 退出浏览器
      def quit_browser(self):
          self.driver.quit()
      # 浏览器前进操作
      def forward(self):
          self.driver.forward()
      # 浏览器后退操作
      def back(self):
          self.driver.back()
      # 隐式等待
      def wait(self, seconds):
          self.driver.implicitly_wait(seconds)
      # 查找元素
      def find_element(self, selector):
          selector_by = selector['find_type']
          selector_value = selector['element_info']
          try:
              if selector_by == 'id':
                  el = self.driver.find_element_by_id(selector_value)
              elif selector_by == "n" or selector_by == 'name':
                  el = self.driver.find_element_by_name(selector_value)
              elif selector_by == 'cs' or selector_by == 'css_selector':
                  el = self.driver.find_element_by_css_selector(selector_value)
              elif selector_by == 'cn' or selector_by == 'classname':
                  el = self.driver.find_element_by_class_name(selector_value)
              elif selector_by == "lt" or selector_by == 'link_text':
                  el = self.driver.find_element_by_link_text(selector_value)
              elif selector_by == "plt" or selector_by == 'partial_link_text':
                  el = self.driver.find_element_by_partial_link_text(selector_value)
              elif selector_by == "tn" or selector_by == 'tag_name':
                  el = self.driver.find_element_by_tag_name(selector_value)
              elif selector_by == "x" or selector_by == 'xpath':
                  el = self.driver.find_element_by_xpath(selector_value)
              elif selector_by == "ss" or selector_by == 'selector_selector':
                  el = self.driver.find_element_by_css_selector(selector_value)
              else:
                  raise NameError("Please enter a valid type of targeting elements.")
          except NoSuchElementException  :
              logger.error("{0}页面中未能找到{1}元素".format(self, selector_value))
          return el
      # 输入
      def input(self, selector, text):
          el = self.find_element(selector)
          try:
              el.clear()
              el.send_keys(text)
              logger.info("Had type \' %s \' in inputBox" % text)
          except NameError as e:
              logger.error("Failed to type in input box with %s" % e)
      # 点击
      def click(self, selector):
          el = self.find_element(selector)
          try:
              logger.info("The element \' %s \' was clicked." % el.text)
              el.click()
          except NameError as e:
              logger.error("Failed to click the element with %s" % e)
      @staticmethod
      def sleep(seconds):
          time.sleep(seconds)
          logger.info("Sleep for %d seconds" % seconds)
      def get_text(self,selector):
          el = self.find_element(selector)
          try:
              return el.text
          except NameError as e:
              logger.error("Failed to text the element with %s" % e)
      def switch_frame(self, selector):
          """
          多表单嵌套切换
          :param loc: 传元素的属性值
          :return: 定位到的元素
          """
          try:
              el = self.find_element(selector)
              return self.driver.switch_to_frame(el)
          except NoSuchElementException as e:
              logger.error("查找iframe异常-> {0}".format(e))
      def switch_windows(self, selector):
          """
          多窗口切换
          :param loc:
          :return:
          """
          try:
              el = self.find_element(selector)
              return self.driver.switch_to_window(el)
          except NoSuchElementException as e:
              logger.error("查找窗口句柄handle异常-> {0}".format(e))
      def switch_alert(self):
          """
          警告框处理
          :return:
          """
          try:
              return self.driver.switch_to_alert()
          except NoSuchElementException as e:
              logger.error("查找alert弹出框异常-> {0}".format(e))

  LoginPage.py —— CNDS登录页面

from  pageObject.basePage import *
  from selenium import webdriver
  from common.readFile import ReadFile
  from config import setting
  login_el = ReadFile().readYaml(setting.TEST_Element_YAML + '/' + 'login.yaml')
  data = ReadFile().readYaml(setting.TEST_DATA_YAML + '/' + 'login_data.yaml')
  class CndsPage(BasePage):
      '''登录页面'''
      url = '/login'
      # 定位器,通过元素属性定位元素对象
      #选择账号密码登录
      chanlelogin_loc = login_el['testcase'][0]
      # 账号输入框
      username_loc = login_el['testcase'][1]
      # 密码输入框
      pwd_loc = login_el['testcase'][2]
      # 单击登录
      login_accout_loc = login_el['testcase'][3]
      def accout_login(self,accout,passwd):
          self.open_url(self.url)
          self.click(self.chanlelogin_loc)
          self.input(self.username_loc,accout)
          self.input(self.pwd_loc,passwd)
          self.click(self.login_accout_loc)
      # 定位器,通过元素属性定位检查项元素对象
      user_login_success_loc = login_el['check'][0]
      accout_id_loc = login_el['check'][1]
      accout_pawd_error_loc = login_el['check'][2]
      # 账号或密码错误提示
      def accout_passwd_error(self):
          return self.get_text(self.accout_pawd_error_loc)
      # 登录成功,跳转到个人资料页,获取用户名
      def get_account(self):
          self.click(self.user_login_success_loc)
          time.sleep(2)
      def user_login_success(self):
          return self.find_element(self.accout_id_loc).text

  组织测试用例

  ·用户名密码正确点击登录

  ·用户名正确,密码错误点击登录

import unittest
  from common import function,myUnit,readFile
  from pageObject.loginPage import CndsPage
  from time import sleep
  from common.logger import Logger
  from config import setting
  import ddt
  log = Logger()
  testData= readFile.ReadFile().readYaml(setting.TEST_DATA_YAML + '/' + 'login_data.yaml')
  @ddt.ddt
  class LoginTest(myUnit.StartEnd):
      # @unittest.skip('skip this case')
      """CNDS登录测试"""
      def user_login_verify(self,account,passwd):
          """
          用户登录
          :param :account 账号
          :param passwd: 密码
          :return:
          """
          CndsPage(self.driver).accout_login(account,passwd)
      @ddt.data(*testData)
      def test_login_normal(self,datayaml):
          log.info("test_login1_normal is start run...")
          self.user_login_verify(datayaml['data']['accout'],datayaml['data']['passwd'])
          sleep(3)
          #断言与截屏
          po = CndsPage(self.driver)
          if datayaml['screenshot'] == 'login_success':
              po.get_account()
              function.inser_img(self.driver)
              self.assertEqual(po.user_login_success(), datayaml['check'][0], "登录成功,返回实际结果是->: {0}".format(po.user_login_success()))
          else:
              function.inser_img(self.driver)
              self.assertEqual(po.accout_passwd_error(), datayaml['check'][0],"登录失败,返回实际结果是->: {0}".format(po.accout_passwd_error()))
          print("test_login1_normal is test end!")

  执行测试用例  

import unittest
  from  common.function import latest_report
  from  common.sendMail import *
  from config import setting
  from thridLib.HTMLTestRunner import HTMLTestRunner
  import time
  import os,sys
  sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
  report_dir = setting.TEST_REPORT + '/report/'
  def add_case(test_path=setting.TEST_DIR):
      discover = unittest.defaultTestLoader.discover(test_path, pattern="test*.py")
      return discover
  def run_case(all_case,result_path=report_dir):
      print("start run testcase...")
      now = time.strftime("%Y-%m-%d %H_%M_%S")
      report_name = result_path + '/' + now + 'result.html'
      print("start write report...")
      #HTMLTestRunner测试报告
      with open(report_name, 'wb') as f:
          runner = HTMLTestRunner(stream=f, title='测试报告', description='用例执行情况')  # 定义测试报告
          runner.run(all_case)  # 执行测试用例
      f.close()
      print("find latest report...")
      # 查找最新的测试报告
      report = latest_report(result_path)
      # 邮件发送报告
      print("send email report...")
      send_mail(report)
      print("test end!")
  if __name__ == '__main__':
      cases = add_case()
      run_case(cases)

 

 作为一位过来人也是希望大家少走一些弯路,在这里我给大家分享一些自动化测试前进之路的必须品,希望能对你带来帮助。(WEB自动化测试、app自动化测试、接口自动化测试、持续集成、自动化测试开发、大厂面试真题、简历模板等等),相信能使你更好的进步!

留【自动化测试】即可【自动化测试交流】:574737577(备注ccc)icon-default.png?t=N5F7http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=hIqEQD5B5ZyLT0S-vFq64p5MCDBc8jJU&authKey=O%2B3T95fjNUNsYxXnPIrOxvkb%2BbuFd1AxuUP5gCbos34AQDjaRG2L6%2Fm9gGakvo94&noverify=0&group_code=574737577

 

 

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

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

相关文章

直接选择排序及其稳定性分析

直接选择排序 直接选择排序是一种很直观的排序方法。其操作是这样:先在未排序的序列中选择最小的元素(或最大的元素),把它与第一个元素交换,放在第一个位置,再在剩余未排序序列中选择第二小的,…

驾驭Dubbo:探索其核心概念与突出特性,助力分布式系统升级

1、Dubbo简介 Apache Dubbo 是一款 RPC 服务开发框架,用于解决微服务架构下的服务治理与通信问题,官方提供了 Java、Golang 等多语言 SDK 实现。使用 Dubbo 开发的微服务原生具备相互之间的远程地址发现与通信能力, 利用 Dubbo 提供的丰富服…

147-Prolixe-KeygenMe#1

Exeinfo查壳,发现没有壳,是Delphi程序 OD字符串搜索,找到关键位置,发现一个关键的call,和一个strcmp比较函数。 进入关键call进行分析,结合IDA。 分析这个call,发现输入的name字符串长度必须…

北欧又一国家布局量子

光子盒研究院 6 月 8 日,挪威奥斯陆城市大学、Simula 研究实验室在内的QCNorway研讨会团队撰写了一份立场文件,其中,对新兴的挪威量子战略提出了建议。 “世界正在接近一场量子革命——一个为期40年的梦想,利用量子力学的现象使计…

学习笔记之法理学

目录 法理学第一节 法的概述一、法的概念二 法的特征三、法的作用(一)法的规范作用(教预引制评)1. 指引作用2.评价作用3.预测作用4.强制作用5.教育作用 (二)法的社会作用(考察较少,两个考点) 四…

浅谈医院电气火灾的起因与预防

摘要:医院属公共场所,建筑密集,人员集中,且弱势群体(病人)居多,一旦发生火灾,可能造成重大财产损失和人员伤亡。在引起医院火灾的各种因素中,电气火灾由于医院建筑功能与其他建筑不同…

网络安全自学秘籍

前言 想学网络安全但是无从下手的小白看过来,非常系统的学习资料,无数小白看了这份资料都已经成功入门,涵盖多个网络安全知识点,我愿称之为网络安全自学宝典。 一、概念性知识 1、了解什么是网络安全 2、清楚法律法规 3、网络安…

【Java】java中接口幂等性解决方案

文章目录 一、概念二、场景三、解决方案3.1、数据库唯一标识3.2、乐观锁3.3、悲观锁3.4、Token机制3.5、分布式锁 四、总结 一、概念 一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数…

shape_based_matching lineMod开源代码学习

github开源代码地址: https://github.com/meiqua/shape_based_matching 针对匹配精度问题,原作者采用了sub-pixel icp的方法进行了最后的finetune,涉及到的相关原理可以查看:亚像素边缘提取与ICP2D的理解 - 知乎 涉及到的论文…

Precision Neuroscience提出第7层皮层接口:可扩展的微创脑机接口平台

大脑皮层包含六层结构,美国精密神经科学公司(Precision Neuroscience Corporation)的研究人员提出了第7层皮层接口:可拓展的微创脑机接口平台。构建了一种模块化的和可拓展的脑机接口平台,包括高通量薄膜电极阵列和微创…

新加坡市场扩张指南:品牌布局策略与挑战解析

随着全球化的发展和市场竞争的加剧,越来越多的企业开始考虑将业务拓展到新的市场。其中,新加坡作为一个经济繁荣、政治稳定、文化多元的国家,成为许多品牌出海的首选目的地之一。然而,要在这个激烈竞争的市场中取得成功&#xff0…

绘制stm32最小系统板

原理图: 不使用串口烧录,所以BOOT0和BOOT1都接地。 VDD:就是单片机的供电电压。 VDDA:VDD后面有个A,AAnalog,表示模拟的意思,就是芯片内部模拟器件的工作电压。 VSSA:表示模拟器件…

2023 Softing暑期培训计划

通过以实践为导向的培训课程提高能力 Softing将在2023年暑期为您提供全面的培训课程。在Softing线上研讨会中,您将体验到结构紧凑的培训课程,包含实用的用户问题讨论以及完善的理论知识交流,而无需学习冗长而枯燥的标准。无论您是初学者还是…

Unittest二次开发实战

目录 前言 unittest.TestResult类简介 TestResult类定制目标 实现步骤 测试结果summary格式规划 单个用例结果格式规划 用例tags和level的实现 根据测试方法对象获取用例代码 单个用例结果类的实现 TestResult属性及初始化方法 测试开始和测试结束 用例开始和用例结束 1. 重写恢…

Python面向对象编程2-面向过程的银行账号模拟程序 项目2.3 单个账户完整项目版本1

项目总目标:用面向过程思想设计一个简单的银行账号模拟程序。本次将迭代多个程序版本,每个版本都将添加更多功能。虽然这些程序没有达到发布的质量标准,但整个项目的目的是关注于代码如何与一个或多个银行账户的数据进行交互。 分析项目的必…

Windows11 WSL子系统ubuntu22.04 修改hostname

大家都知道以往我们修改 Linux系统的 hostname只要修改 /etc/hostname 这个文件中的名字即可,但是在WSL中修改该文件是无法生效的。 要修改Hostname并使它生效,我们必须修改 /etc/wsl.conf 文件。 编辑配置文件 sudo vi /etc/wsl.conf修改参数 将 ho…

SQL优化--如何定位慢查询?

目录 概述 检测方案 方案一:开源工具 方案二:MySQL自带慢日志 面试回答 大纲 范例 概述 在SQL中,“慢查询”是指执行速度较慢的数据库查询操作。 一般来说聚合查询,多表查询,表数据量过大查询,深度…

埃及极简史

埃及全称为阿拉伯埃及共和国,位于北非东部,领土还包括苏伊士运河以东、亚洲西南端的西奈半岛,埃及既是亚、非之间的陆地交通要冲,也是大西洋于印度洋之间海上航线的捷径,战略位置十分重要。 古埃及是古代四大文明古国之…

龙蜥白皮书精选:Ancert——硬件兼容性验证与守护

文/硬件兼容性 SIG Ancert 是龙蜥操作系统硬件兼容性测试套件,致力于验证硬件设备集成商等厂商发布的整机服务器和各种板卡外设与龙蜥操作系统 不同版本之间的兼容性,推动社区发行版在各种硬件设备上的适配,围绕龙蜥操作系统建立完善的硬件生…

Linux运维监控学习笔记5

监控项和应用集(重点) 监控项(item):监控项是从主机收集的信息。一个监控项是一个独立的子标,代表收集数据或监控的最小的单位。 应用集(applications):代表多个监控项…