• 7
  • 7
分享

  项目背景

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

  功能实现

  ·自动运行用例

  ·自动生成测试报告

  ·自动断言与截图

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

  ·数据,页面元素分离

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

  ·执行日志、分布式执行

  项目架构

5-1.png

  浏览器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)

   

5-2.png



作者:平凡之路

来源:https://www.cnblogs.com/watery/p/13929116.html

  • 【留下美好印记】
    赞赏支持
登录 后发表评论
+ 关注

热门文章

    最新讲堂

      • 推荐阅读
      • 换一换
          • 本文由 Dify 深度用户@李昱昊 投稿整理所得。基于 Dify 能力进行 AI 应用的创建,产出本篇最佳实践文章。我们欢迎更多优秀开发者向我们投稿最佳实践,投稿联系邮箱:hello@dify.ai,或加入 Discord 社群( https://discord.com/invite/FngNHpbcY7 ) 联系官方工作人员。Dify 允许创建 AI 应用,并提供二次开发的能力。这里我将演示创建一个法律问答助手的 AI 应用(机器人),称作“知法”。在本篇教程中,我将指导你为“知法”接入企业微信。前置准备企业微信的管理员权限;一个 Dify 的帐号(https://dify.ai/);一个 ...
            0 0 1216
            分享
          • 测试人员进行的测试活动,不是仅限于版本上线前的测试,版本上线后,我们的测试工作依然在继续,只不过测试环境变成了线上环境,测试力度变为走查形式,一些异常或者特殊场景等会相应减少,但是常用功能和正向流程一个都不能少。以下来简单拆解下线上走查的一些注意事项。~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~测试走查,是我们每个测试工程师的日常工作:版本迭代前,通过需求评审,发现现有功能的已知问题;版本进行中,通过测试设计,审视当前测试方案存在的没考虑全的问题;或者开发的设计方案漏洞版本开发时,通过用例评审和迭代测试,审...
            1 0 6123
            分享
          • 随着技术的进步,测试解决方案变得更具可扩展性,加速了团队从手动测试到Selenium测试自动化的转型。但是成年人的世界,没有什么是容易的。对于许多团队来说,并行运行多个测试仍然是不可扩展的。他们倾向于遵循传统的顺序执行测试方法,但是这需要大量时间、精力。这时候,就需要一种更加高效的测试方法,来解决这些问题。# 并行测试并行测试是指在多个计算机或处理器上同时运行测试用例,以提高测试效率和准确性的测试方法。通过并行测试,可以大大缩短测试执行时间,从而提高测试效率,并且可以发现更多的缺陷,提高测试覆盖率和测试质量。通过并行测试,可以加快测试的速度,同时也可以更快地发现潜在的问题。当测试自动化框架与云...
            0 0 1331
            分享
          •   之前小编有和大家讲到测试思维,今天来讲一下思维的直接体现是什么——测试用例。  测试用例包括的元素:功能/模块,测试标题,前置条件,优先级,测试步骤,预期结果。这些是用例中必须有的字段,除了测试标题,其他都很好写的。下面重点讲解测试标题。测试标题也叫测试点,测试是分析设计的结果。  分析是分析需求,分系统,分析业务,甚至分行业。这样才能知道测试对象是什么行业的什么系统,有什么功能,哪些是核心,哪些是非核心。  设计是设计测试数据用来执行的。这个数据不用十分具体,也包括不同的测试条件和场景。  测试点形成方法有:等价类,边界值,流程图,场景法,因果图,错误推测法。这几个是基础,也是非常常用的...
            0 0 869
            分享
          • 测试用例阶段场景用例覆盖--增加开发对需求的全局理解深度已确认优化需求重点提醒--确保开发和测试对需求的信息同步提供开发自测用例--增加开发自测的认知在测试用例评审阶段,也就是程序开发阶段,用例覆盖率尽可能的全面,能进一步提高开发设计方法或对业务逻辑的理解,减少不必要的缺陷产生。测试阶段测试整体至少分为三轮:测试环境:核心测试,包括ui细节、字段规则、逻辑 校验等。(时间占比:60%)预生产环境:二次进行全流程场景测试(时间占比:30%)上线tag验证:确保代码合并到master后没有问题(时间占比:10%)代码扫描/错误监测:sonar声呐代码扫描工具,检测开发代码一些常规的语法规则错误;b...
            0 0 1341
            分享
      • 51testing软件测试圈微信