python selenium自动化测试框架搭建的方法步骤


Posted in Python onJune 14, 2020

设计思路

本文整理归纳以往的工作中用到的东西,现汇总成基础测试框架提供分享。

框架采用python3 + selenium3 + PO + yaml + ddt + unittest等技术编写成基础测试框架,能适应日常测试工作需要。

1、使用Page Object模式将页面定位和业务操作分开,分离测试对象(元素对象)和测试脚本(用例脚本),一个页面建一个对象类,提高用例的可维护性;

2、使用yaml管理页面控件元素数据和测试用例数据。例如元素ID等发生变化时,不需要去修改测试代码,只需要在对应的页面元素yaml文件中修改即可;

3、分模块管理,互不影响,随时组装,即拿即用。

GitHub项目地址:https://github.com/yingoja/DemoUI

测试框架分层设计

python selenium自动化测试框架搭建的方法步骤

  • 把常见的操作和查找封装成基础类,不管是什么产品,可直接拿来复用
  • 业务层主要是封装对象页面类,一个页面建一个类,业务层页面继承基础层
  • 用例层针对产品页面功能进行构造摸拟执行测试
  • 框架层提供基础组件,支撑整个流程执行及功能扩展,给用例层提供各页面的元素数据、用例测试数据,测试报告输出等

测试框架目录结构

python selenium自动化测试框架搭建的方法步骤

如下思维导图目录结构介绍:

python selenium自动化测试框架搭建的方法步骤

编写用例方法

login.yaml

testinfo:
    - id: test_login001
     title: 登录测试
     info: 打开抽屉首页
 testcase:
    - element_info: login-link-a
     find_type: ID
     operate_type: click
     info: 打开登录对话框
    - element_info: mobile
     find_type: ID
     operate_type: send_keys
     info: 输入手机号
    - element_info: mbpwd
     find_type: ID
     operate_type: send_keys
     info: 输入密码
    - element_info: //input[@class='keeplogin']
     find_type: XPATH
     operate_type: click
     info: 单击取消自动登录单选框
    - element_info: //span[text()='登录']
     find_type: XPATH
     operate_type: click
     info: 单击登录按钮
    - element_info: userProNick
     find_type: ID
     operate_type: perform
     info: 鼠标悬停账户菜单
    - element_info: //a[@class='logout']
     find_type: XPATH
     operate_type: click
     info: 选择退出
 check:
    - element_info: //div[@class='box-mobilelogin']/div[1]/span
     find_type: XPATH
     info: 检查输入手机号或密码,登录异常提示
    - element_info: userProNick
     find_type: ID
     info: 成功登录
    - element_info: reg-link-a
     find_type: ID
     info: 检查退出登录是否成功

例如,我们要新增登录功能测试用例:

首先,只需在testyaml目录下新增一个页面对象yaml文件,参考login.yaml格式编写即可。这些文件是提供给封装页面对象类调用并执行定位识别操作。

login_data.yaml

-
  id: test_login001.1
  detail : 手机号和密码为空登录
  screenshot : phone_pawd_empty
  data:
   phone: ""
   password: ""
  check :
    - 手机号不能为空
 -
  id: test_login001.2
  detail : 手机号为空登录
  screenshot : phone_empty
  data :
   phone: ""
   password : aa
  check :
   - 手机号不能为空
 -
  id: test_login001.3
  detail : 密码为空登录
  screenshot : pawd_empty
  data :
   phone : 13511112222
   password: ""
  check :
   - 密码不能为空
 -
  id: test_login001.4
  detail : 非法手机号登录
  screenshot : phone_error
  data :
   phone : abc
   password: aa
  check :
   - 手机号格式不对
 -
  id: test_login001.5
  detail : 手机号或密码不匹配
  screenshot : pawd_error
  data :
   phone : 13511112222
   password: aa
  check :
   - 账号密码错误
 -
  id: test_login001.6
  detail : 手机号和密码正确
  screenshot : phone_pawd_success
  data :
   phone : 13865439800
   password: ********
  check :
   - yingoja
 
 login_data.yaml

login_data.yaml

其次,在testdata目录下新增一个login_data.yaml文件提供给登录接口传参的测试数据,编写格式参考login_data.yaml文件。

loginPage.py

#!/usr/bin/env python
 # _*_ coding:utf-8 _*_
  __author__ = 'YinJia'
  
  import os,sys
  sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
  from config import setting
  from selenium.webdriver.support.select import Select
  from selenium.webdriver.common.action_chains import ActionChains
 from selenium.webdriver.common.by import By
 from public.page_obj.base import Page
 from time import sleep
 from public.models.GetYaml import getyaml
 
 testData = getyaml(setting.TEST_Element_YAML + '/' + 'login.yaml')
 
 class login(Page):
   """
   用户登录页面
   """
   url = '/'
   dig_login_button_loc = (By.ID, testData.get_elementinfo(0))
   def dig_login(self):
     """
     首页登录
     :return:
     """
     self.find_element(*self.dig_login_button_loc).click()
     sleep(1)
 
   # 定位器,通过元素属性定位元素对象
   # 手机号输入框
   login_phone_loc = (By.ID,testData.get_elementinfo())
   # 密码输入框
   login_password_loc = (By.ID,testData.get_elementinfo())
   # 取消自动登录
   keeplogin_button_loc = (By.XPATH,testData.get_elementinfo())
   # 单击登录
   login_user_loc = (By.XPATH,testData.get_elementinfo())
   # 退出登录
   login_exit_loc = (By.ID, testData.get_elementinfo())
   # 选择退出
   login_exit_button_loc = (By.XPATH,testData.get_elementinfo())
 
   def login_phone(self,phone):
     """
     登录手机号
     :param username:
     :return:
     """
     self.find_element(*self.login_phone_loc).send_keys(phone)
 
   def login_password(self,password):
     """
     登录密码
     :param password:
     :return:
     """
     self.find_element(*self.login_password_loc).send_keys(password)
 
   def keeplogin(self):
     """
     取消单选自动登录
     :return:
     """
     self.find_element(*self.keeplogin_button_loc).click()
 
   def login_button(self):
     """
     登录按钮
     :return:
     """
     self.find_element(*self.login_user_loc).click()
 
   def login_exit(self):
     """
     退出系统
     :return:
     """
     above = self.find_element(*self.login_exit_loc)
     ActionChains(self.driver).move_to_element(above).perform()
     sleep(2)
     self.find_element(*self.login_exit_button_loc).click()
 
   def user_login(self,phone,password):
     """
     登录入口
     :param username: 用户名
     :param password: 密码
     :return:
     """
     self.open()
     self.dig_login()
     self.login_phone(phone)
     self.login_password(password)
     sleep(1)
     self.keeplogin()
     sleep(1)
     self.login_button()
     sleep(1)
 
  phone_pawd_error_hint_loc = (By.XPATH,testData.get_CheckElementinfo(0))
  user_login_success_loc = (By.ID,testData.get_CheckElementinfo(1))
   exit_login_success_loc = (By.ID,testData.get_CheckElementinfo(2))
 
   # 手机号或密码错误提示
   def phone_pawd_error_hint(self):
     return self.find_element(*self.phone_pawd_error_hint_loc).text
 
   # 登录成功用户名
   def user_login_success_hint(self):
     return self.find_element(*self.user_login_success_loc).text
 
   # 退出登录
   def exit_login_success_hint(self):
     return self.find_element(*self.exit_login_success_loc).text

然后,在page_obj目录下新增一个loginPage.py文件,是用来封装登录页面对象类,执行登录测试流程操作。

login_sta.py

#!/usr/bin/env python
 # _*_ coding:utf-8 _*_
 __author__ = 'YinJia'
 
 
 import os,sys
 sys.path.append(os.path.dirname(os.path.dirname(__file__)))
 import unittest,ddt,yaml
 from config import setting
 from public.models import myunit,screenshot
 from public.page_obj.loginPage import login
 from public.models.log import Log
 
 try:
   f =open(setting.TEST_DATA_YAML + '/' + 'login_data.yaml',encoding='utf-8')
   testData = yaml.load(f)
 except FileNotFoundError as file:
   log = Log()
   log.error("文件不存在:{0}".format(file))
 
 @ddt.ddt
 class Demo_UI(myunit.MyTest):
   """抽屉新热榜登录测试"""
   def user_login_verify(self,phone,password):
     """
     用户登录
     :param phone: 手机号
     :param password: 密码
     :return:
     """
     login(self.driver).user_login(phone,password)
 
   def exit_login_check(self):
     """
     退出登录
     :return:
     """
     login(self.driver).login_exit()
 
   @ddt.data(*testData)
   def test_login(self,datayaml):
     """
     登录测试
     :param datayaml: 加载login_data登录测试数据
     :return:
     """
     log = Log()
    log.info("当前执行测试用例ID-> {0} ; 测试点-> {1}".format(datayaml['id'],datayaml['detail']))
     # 调用登录方法
     self.user_login_verify(datayaml['data']['phone'],datayaml['data']['password'])
     po = login(self.driver)
     if datayaml['screenshot'] == 'phone_pawd_success':
       log.info("检查点-> {0}".format(po.user_login_success_hint()))
       self.assertEqual(po.user_login_success_hint(), datayaml['check'][0], "成功登录,返回实际结果是->: {0}".format(po.user_login_success_hint()))
       log.info("成功登录,返回实际结果是->: {0}".format(po.user_login_success_hint()))
       screenshot.insert_img(self.driver, datayaml['screenshot'] + '.jpg')
       log.info("-----> 开始执行退出流程操作")
       self.exit_login_check()
       po_exit = login(self.driver)
       log.info("检查点-> 找到{}元素,表示退出成功!".format(po_exit.exit_login_success_hint()))
       self.assertEqual(po_exit.exit_login_success_hint(), '注册',"退出登录,返回实际结果是->: {0}".format(po_exit.exit_login_success_hint()))
       log.info("退出登录,返回实际结果是->: {0}".format(po_exit.exit_login_success_hint()))
     else:
       log.info("检查点-> {0}".format(po.phone_pawd_error_hint()))
       self.assertEqual(po.phone_pawd_error_hint(),datayaml['check'][] , "异常登录,返回实际结果是->: {}".format(po.phone_pawd_error_hint()))
       log.info("异常登录,返回实际结果是->: {0}".format(po.phone_pawd_error_hint()))
       screenshot.insert_img(self.driver,datayaml['screenshot'] + '.jpg')
 
 if __name__=='__main__':
   unittest.main()

最后,在testcase目录下创建测试用例文件login_sta.py,采用ddt数据驱动读取yaml测试数据文件

综上所述,编写用例方法只需要按以上四个步骤创建->编写即可。

执行如下主程序,可看输出的实际结果。

#!/usr/bin/env python
# _*_ coding:utf-8 _*_
__author__ = 'YinJia'

import os,sys
sys.path.append(os.path.dirname(__file__))
from config import setting
import unittest,time
from package.HTMLTestRunner import HTMLTestRunner
from public.models.newReport import new_report
from public.models.sendmail import send_mail

# 测试报告存放文件夹,如不存在,则自动创建一个report目录
if not os.path.exists(setting.TEST_REPORT):os.makedirs(setting.TEST_REPORT + '/' + "screenshot")

def add_case(test_path=setting.TEST_DIR):
  """加载所有的测试用例"""
  discover = unittest.defaultTestLoader.discover(test_path, pattern='*_sta.py')
  return discover

def run_case(all_case,result_path=setting.TEST_REPORT):
  """执行所有的测试用例"""
  now = time.strftime("%Y-%m-%d %H_%M_%S")
  filename = result_path + '/' + now + 'result.html'
  fp = open(filename,'wb')
  runner = HTMLTestRunner(stream=fp,title='抽屉新热榜UI自动化测试报告',
              description='环境:windows 7 浏览器:chrome',
              tester='Jason')
  runner.run(all_case)
  fp.close()
  report = new_report(setting.TEST_REPORT) #调用模块生成最新的报告
  send_mail(report) #调用发送邮件模块

if __name__ =="__main__":
  cases = add_case()
  run_case(cases)

测试结果展示

HTML报告日志

python selenium自动化测试框架搭建的方法步骤

HTML报告点击截图,弹出截图

python selenium自动化测试框架搭建的方法步骤

测试报告通过的日志

python selenium自动化测试框架搭建的方法步骤

自动截图存放指定的目录

python selenium自动化测试框架搭建的方法步骤

邮件测试报告

python selenium自动化测试框架搭建的方法步骤

到此这篇关于python selenium自动化测试框架搭建的方法步骤的文章就介绍到这了,更多相关python selenium自动化测试框架搭建内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

作者:YinJia
出处:http://www.cnblogs.com/yinjia/

Python 相关文章推荐
python实现网页链接提取的方法分享
Feb 25 Python
python根据开头和结尾字符串获取中间字符串的方法
Mar 26 Python
Python使用sqlalchemy模块连接数据库操作示例
Mar 13 Python
python flask解析json数据不完整的解决方法
May 26 Python
python3+PyQt5 自定义窗口部件--使用窗口部件样式表的方法
Jun 26 Python
mac系统下Redis安装和使用步骤详解
Jul 09 Python
python实现文件的分割与合并
Aug 29 Python
pytorch 模型的train模式与eval模式实例
Feb 20 Python
django 利用Q对象与F对象进行查询的实现
May 15 Python
python 利用opencv实现图像网络传输
Nov 12 Python
解决numpy数组互换两行及赋值的问题
Apr 17 Python
Python+DeOldify实现老照片上色功能
Jun 21 Python
Python如何使用paramiko模块连接linux
Mar 18 #Python
Python selenium页面加载慢超时的解决方案
Mar 18 #Python
Python Selenium 设置元素等待的三种方式
Mar 18 #Python
Python多线程threading join和守护线程setDeamon原理详解
Mar 18 #Python
Python semaphore evevt生产者消费者模型原理解析
Mar 18 #Python
Python中remove漏删和索引越界问题的解决
Mar 18 #Python
Python集成开发工具Pycharm的安装和使用详解
Mar 18 #Python
You might like
PHP中删除变量时unset()和null的区别分析
2011/01/27 PHP
PHP cURL初始化和执行方法入门级代码
2015/05/28 PHP
浅析ThinkPHP缓存之快速缓存(F方法)和动态缓存(S方法)(日常整理)
2015/10/26 PHP
PHP实现搜索地理位置及计算两点地理位置间距离的实例
2016/01/08 PHP
基于jquery用于查询操作的实现代码
2010/05/10 Javascript
jQuery选择没有colspan属性的td的代码
2010/07/06 Javascript
JQuery与JS里submit()的区别示例介绍
2014/02/17 Javascript
js的参数有长度限制吗?发现不能超过2083个字符
2014/04/20 Javascript
ExtJS4利根据登录后不同的角色分配不同的树形菜单
2014/05/02 Javascript
JavaScript弹出新窗口并控制窗口移动到指定位置的方法
2015/04/06 Javascript
Javascript中判断对象是否为空
2015/06/10 Javascript
jQuery实现下拉框功能实例代码
2016/05/06 Javascript
微信小程序 视图层(xx.xml)和逻辑层(xx.js)详细介绍
2016/10/13 Javascript
JS实现Ajax的方法分析
2016/12/20 Javascript
js获取元素的偏移量offset简单方法(必看)
2017/07/05 Javascript
详解vue.js移动端导航navigationbar的封装
2017/07/05 Javascript
vue中实现移动端的scroll滚动方法
2018/03/03 Javascript
vue改变对象或数组时的刷新机制的方法总结
2019/04/24 Javascript
Flexible.js可伸缩布局实现方法详解
2020/11/13 Javascript
Python中用于去除空格的三个函数的使用小结
2015/04/07 Python
python 禁止函数修改列表的实现方法
2017/08/03 Python
Python机器学习之决策树算法实例详解
2017/12/06 Python
使用APScheduler3.0.1 实现定时任务的方法
2019/07/22 Python
如何教少儿学习Python编程
2020/07/10 Python
美国指甲油品牌:Deco Miami
2017/01/30 全球购物
Brookstone美国官网:独特新奇产品
2017/03/04 全球购物
CPB肌肤之钥美国官网:Clé de Peau Beauté
2017/09/05 全球购物
全球才华横溢工匠的家居装饰、珠宝和礼物:NOVICA
2021/01/22 全球购物
linux下进程间通信的方式
2013/01/23 面试题
幼儿园数学教学反思
2014/02/02 职场文书
温馨提示标语
2014/06/26 职场文书
廉政文化进校园广播稿
2014/10/20 职场文书
贫民窟的百万富翁观后感
2015/06/09 职场文书
Python 实现绘制子图及子图刻度的变换等问题
2021/05/31 Python
javascript代码简写的几种常用方式汇总
2021/08/23 Javascript
各国货币符号大全
2022/02/17 杂记