python3+selenium自动化测试框架详解


Posted in Python onMarch 17, 2019

背景

为了更好的发展自身的测试技能,应对测试行业以及互联网行业的迭代变化。自学python以及自动化测试。

虽然在2017年已经开始接触了selenium,期间是断断续续执行自动化测试,因为还有其他测试任务,培训任务要执行…
前期建议大家能够学习python基本语法(python基础教程)

任务

搭建自动化测试框架,并能有效方便的进行测试,维护成本也要考虑其中。

过程

我的自动化框架可能不成熟,因为是自学的。请多包涵。也请大佬指导~

python3+selenium自动化测试框架详解

common

包含:基本的公共方法类,比如HTML报告、Log处理、发送邮件、基本页面对象等

其中pageObject里面是对各个测试系统操作页面的一个封装,以后用例的方法直接继承即可。可多次调用,维护起来比较方便。

conf

基本的系统参数配置信息,可以包含url,正确用户的信息,简单日志级别,某些输出位置,邮件信息等

data

对于数据驱动或者其他测试用例中需要测试的数据,之后测试用例流程不变,可以直接在文档中进行测试数据的修改。暂时采用excel。也可以采用csv,xml等等方法

log

日志输出,暂时包括了 log输出,htmlreport输出以及img的保存。

test

其中包含testcase以及testsuite两个模块

testcase 负责编写测试用例如果某个功能有多个py文件编写可以再新建一个目录。
testsuite 就是测试套件,可以按需求进行选择需要的测试项(包含测试用例以及测试类)
注意:使用ddt则不可以再使用addTest方式单独添加测试用例了。

1

代码部分

- common中的BasePage

class BasePage():
 global logg
 logg = LogHandler().logger
 def __init__(self,driver,url=None):
  self.wd = driver
  self.wd.implicitly_wait(5)
  self.actions = ActionChains(self.wd)
  if url :
   self.url = url
  else:
   self.url = self.server_url_conf()
 #浏览器行为的一些方法
 def get_conf_url(self):
		self.wd.get(self.url)
  self.wd.maximize_window()
  logg.debug("enter conf_url : " + str(self.url))
 def brower_close(self):
  return self.wd.close()
 def brower_quit_all(self):
  return self.wd.quit()
... 	下面还有刷新,前进后退等

 #定位 这里通过 By.xx 方法
 def find_web_element(self,*loc):
  #self.wd.find_element(*loc)
  return self.wd.find_element(*loc)

 #元素操作
 def type_text(self,loc,text):
  return self.wd.find_element(*loc).send_keys(text)
  
 def clear_text(self,*loc):
  return self.wd.find_element(*loc).clear()
  
 def submit_func(self,*loc):
  return self.wd.find_element(*loc).submit()

 def click_btn(self,*loc):
  return self.wd.find_element(*loc).click()
  
	#鼠标相关
 def mouse_move_to_element(self,*loc):
  elem = self.find_web_element(*loc)
  self.actions.move_to_element(elem).perform()
... 下面还有点击,双击,右击的一些方法  

 #获取信息行为
 def get_web_url(self):
  return self.wd.current_url
 def get_title(self):
  return self.wd.title
 def get_element_text(self,*loc):
  return self.find_web_element(*loc).text

 #元素是否存在 是 True
 def check_element_isexist(self,loc):
  isexist = False
  try:
   EC.presence_of_element_located(loc)(self.wd)
   isexist = True
  except Exception as e:
   isexist = False
   logg.debug(' isexist or not :',exc_info = True)
  return isexist
 def check_element_has_text(self,loc,text):
		pass #省略
 
 def check_element_isdisplayed(self,*loc):
  	pass #省略
  	
 #生成图
 def __inser_img(self,passorfailed,imgname):
  time_loc = time.strftime("%m%d_%H%M%S",time.localtime())
  file_path = os.path.abspath(__file__)
  file_path = os.path.join(file_path+"/../../log/%s_%s.png" %(imgname,time_loc))
  self.wd.get_screenshot_as_file(file_path)
  logg.debug('insert_%s_img %s ' %(passorfailed,(file_path)))

 def insert_error_img(self,imgname):
  self.__inser_img("error",imgname)
 def insert_success_img(self,imgname):
  self.__inser_img("success",imgname)
 def insert_debug_img(self,imgname):
  self.__inser_img("debug",imgname)


 def server_url_conf(self):
  self.host = readconfig.ReadConfig().getserver('host')
  self.port = readconfig.ReadConfig().getserver('port')
  urlvalue = self.host + ":" + self.port

  return urlvalue

if __name__ == '__main__':
 test = BasePage(webdriver.Chrome())
 test.get_conf_url()

common中登录页的页面对象

包含了页面的一些方法比如

输入用户名,输入密码,点击登录

test中的 logintestcase

则直接使用 登录页面对象的 输入用户名,输入密码,点击登录即可

后期维护,如果元素变动,则只需要修改页面对象代码而对用例则无需修正

class AioLogin(BasePage):
 global logg
 logg = LogHandler().getlog()
 username_loc = (By.NAME, "username")
 password_loc = (By.CSS_SELECTOR, "input[type='password']")
 login_loc = (By.CLASS_NAME, "login-btn")
 login_loc_oem = (By.ID,"submit")
 check_login_loc = (By.CLASS_NAME,"error-tip")
 elements = [username_loc,password_loc,login_loc,check_login_loc]
 log_menu = (By.CSS_SELECTOR,"[name='log']")
 logg.debug(elements)
 
 def set_username(self,username):
  self.clear_text(*self.username_loc) #直接使用BasePage的方法
  self.type_text(self.username_loc,username)
  logg.info('Enter username: ' + username)
  sleep(0.1)
... 其他

logintest

这里使用了ddt数据驱动方法

from ddt import data,ddt,unpack

@ddt
class TestLogin(unittest.TestCase):
 global logg
 logg = LogHandler().getlog()
 
 @classmethod  #该类方法,执行中只会启动一次。区别于setUp的 每个用例都执行一遍
 def setUpClass(cls):
  cls.test = aiologinpage.AioLogin(webdriver.Chrome())
  cls.test.get_conf_url()
  # print('start TestSearch')
  
 @classmethod
 def tearDownClass(cls):
  # TestLogin().logg.info("brower quit")
  TestLogin().test.brower_close()
  pass
 logindata = ReadExcel().getValue('login')
 
 @data(*logindata)
 @unpack  #当有多组数据时,需要unpack
 def testcase2(self,username,passwd,result):
  logg.info(username+" " + passwd +" " +str(result))
  self.test.set_username(username) #用例直接使用登录页面对象,后期除了修改测试用例,否则无需变动
  self.test.set_password(passwd)
  self.test.type_login_btn()
  
  # 断言登录结果和预期结果是否一致
  self.assertTrue(self.test.check_login_result(result),
      msg="\r login_test fail \r username :%s \r passwd : %s " %(username,passwd))

if __name__ == '__main__':
 unittest.main()

其他页面

比如我有个 创建设备分组的页面

我必须要先登录才可以执行下面的操作

此时,可以从conf中获取成功登录的用户名和密码,把correct_login方法写在登录页面对象中。

def correct_login(self):
  self.get_conf_url()
  self.userpasswd = self.correct_userpasswd_conf()
  self.set_username(self.userpasswd[0])
  self.set_password(self.userpasswd[1])
  self.type_login_btn()

之后,其他页面初始化时候直接调用这个correct_login即可登录

测试套件添加方法
TestSuite方法
#添加一个类
st1 = unittest.makeSuite(TestLogin)
#单独添加多个用例
st = unittest.TestSuite(map(TestClassName,[‘testcase1',‘testcase2']))
st = unittest.TestSuite(TestClaseeName(‘testcase1'))

#添加一个或者多个测试用例
st2 = unittest.TestSuite()
st2.addTests(map(TestCaseClassName,[‘testcase2',‘testcase1']))
st2.addTest(TestCaseClassName(‘testcase1'))
#添加一个类
st2.addTest(unittest.makeSuite(TestClassName))

TestLoader 方法
discovery 发现脚本
st = unittest.TestLoader().discovery(“dir_path”,pattern=“a*.py”)

#loadTestFromTestCase 加载 测试类
st1 = unittest.TestLoader().loadTestsFromTestCase(TestLoginCheck)
st2 = unittest.TestLoader().loadTestsFromTestCase(TestLogin)
stt = unittest.TestSuite()
stt.addTests([st1,st2])

Python 相关文章推荐
讲解python参数和作用域的使用
Nov 01 Python
Python中的Classes和Metaclasses详解
Apr 02 Python
Python实现对PPT文件进行截图操作的方法
Apr 28 Python
Python中的一些陷阱与技巧小结
Jul 10 Python
Python实现变量数值交换及判断数组是否含有某个元素的方法
Sep 18 Python
Python简单读取json文件功能示例
Nov 30 Python
Python之多线程爬虫抓取网页图片的示例代码
Jan 10 Python
浅谈Python爬虫基本套路
Mar 25 Python
pyqt5移动鼠标显示坐标的方法
Jun 21 Python
Python中利用LSTM模型进行时间序列预测分析的实现
Jul 26 Python
基于Django统计博客文章阅读量
Oct 29 Python
python爬取天气数据的实例详解
Nov 20 Python
Django 中间键和上下文处理器的使用
Mar 17 #Python
Python时间和字符串转换操作实例分析
Mar 16 #Python
Python中numpy模块常见用法demo实例小结
Mar 16 #Python
Python常见的pandas用法demo示例
Mar 16 #Python
详解python中list的使用
Mar 15 #Python
详解Python_shutil模块
Mar 15 #Python
python批量修改文件夹及其子文件夹下的文件内容
Mar 15 #Python
You might like
测试php函数的方法
2013/11/13 PHP
php中preg_replace_callback函数简单用法示例
2016/07/21 PHP
浅谈Laravel中的三种中间件的作用
2019/10/13 PHP
JQuery 文本框使用小结
2010/05/22 Javascript
javascript 防止刷新,后退,关闭
2010/08/07 Javascript
JQERY limittext 插件0.2版(长内容限制显示)
2010/08/27 Javascript
jquery 使用点滴函数代码
2011/05/20 Javascript
jQuery实现动态表单验证时文本框抖动效果完整实例
2015/08/21 Javascript
js实现跨域访问的三种方法
2015/12/09 Javascript
详解javascript实现自定义事件
2016/01/19 Javascript
jquery实现可旋转可拖拽的文字效果代码
2016/01/27 Javascript
javascript正则表达式之分组概念与用法实例
2016/06/16 Javascript
JS控制层作圆周运动的方法
2016/06/20 Javascript
jQuery ajaxSubmit 实现ajax提交表单局部刷新
2016/07/04 Javascript
Vue 通过自定义指令回顾v-内置指令(小结)
2018/09/03 Javascript
jQuery中each和js中forEach的区别分析
2019/02/27 jQuery
Vue CLI项目 axios模块前后端交互的使用(类似ajax提交)
2019/09/01 Javascript
通过layer实现可输入的模态框的例子
2019/09/27 Javascript
vue双击事件2.0事件监听(点击-双击-鼠标事件)和事件修饰符操作
2020/07/27 Javascript
[01:38]DOTA2第二届亚洲邀请赛中国区预选赛出线战队晋级之路
2017/01/17 DOTA
Python数据分析matplotlib设置多个子图的间距方法
2018/08/03 Python
Python imread、newaxis用法详解
2019/11/04 Python
已安装tensorflow-gpu,但keras无法使用GPU加速的解决
2020/02/07 Python
基于Python正确读取资源文件
2020/09/14 Python
Ratchet 模态框的实现
2020/08/19 HTML / CSS
专注澳大利亚特产和新西兰特产的澳洲中文网:0061澳洲制造
2019/03/24 全球购物
大学生家政服务项目创业计划书
2014/01/30 职场文书
工作求职自荐信
2014/06/13 职场文书
环境科学专业求职信
2014/08/04 职场文书
爱护公共设施演讲稿
2014/09/13 职场文书
咖啡厅商业计划书
2014/09/15 职场文书
2016大学生毕业实习心得体会
2016/01/23 职场文书
Python进阶学习之带你探寻Python类的鼻祖-元类
2021/05/08 Python
深入理解Vue的数据响应式
2021/05/15 Vue.js
Python Flask请求扩展与中间件相关知识总结
2021/06/11 Python
idea搭建可运行Servlet的Web项目
2021/06/26 Java/Android