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 相关文章推荐
phpsir 开发 一个检测百度关键字网站排名的python 程序
Sep 17 Python
python使用opencv进行人脸识别
Apr 07 Python
Python实现Linux中的du命令
Jun 12 Python
python中如何使用正则表达式的集合字符示例
Oct 09 Python
Python中asyncio模块的深入讲解
Jun 10 Python
python 字典访问的三种方法小结
Dec 05 Python
在PyCharm中实现添加快捷模块
Feb 12 Python
Django在Model保存前记录日志实例
May 14 Python
Django serializer优化类视图的实现示例
Jul 16 Python
用Python 爬取猫眼电影数据分析《无名之辈》
Jul 24 Python
python re模块常见用法例举
Mar 01 Python
pandas中关于apply+lambda的应用
Feb 28 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
vBulletin HACK----显示话题大小和打开新窗口于论坛索引页
2006/10/09 PHP
用来解析.htpasswd文件的PHP类
2012/09/05 PHP
PHP设置图片文件上传大小的具体实现方法
2013/10/11 PHP
php截取中文字符串函数实例
2015/02/23 PHP
七个很有意思的PHP函数
2014/05/12 Javascript
js实现顶部可折叠的菜单工具栏效果实例
2015/05/09 Javascript
Bootstrap基础学习
2015/06/16 Javascript
javascript实现随机显示星星特效
2016/01/28 Javascript
javascript实现label标签跳出循环操作
2016/03/06 Javascript
jQuery实现指定区域外单击关闭指定层的方法【经典】
2016/06/22 Javascript
Javascript中的对象和原型(二)
2016/08/12 Javascript
vue拦截器Vue.http.interceptors.push使用详解
2017/04/22 Javascript
es7学习教程之fetch解决异步嵌套问题的方法示例
2017/07/21 Javascript
Vue2.0如何发布项目实战
2017/07/27 Javascript
Vue2.0实现组件数据的双向绑定问题
2018/03/06 Javascript
简化版的vue-router实现思路详解
2018/10/19 Javascript
微信小程序 可搜索的地址选择实现详解
2019/08/28 Javascript
layui弹出框Tab选项卡的示例代码
2019/09/04 Javascript
微信小程序HTTP请求从0到1封装
2019/09/09 Javascript
JS实现横向轮播图(初级版)
2020/06/24 Javascript
Python实现的ini文件操作类分享
2014/11/20 Python
python list排序的两种方法及实例讲解
2017/03/20 Python
利用python批量给云主机配置安全组的方法教程
2017/06/21 Python
Python3中列表list合并的四种方法
2019/04/19 Python
纯CSS3编写的的精美动画进度条(无flash/无图像/无脚本/附源码)
2013/01/07 HTML / CSS
俄罗斯第一家篮球店:StreetBall
2020/07/30 全球购物
JAVA程序员面试题
2012/10/03 面试题
天地会口号
2014/06/17 职场文书
装修活动策划方案
2014/08/27 职场文书
离婚协议书范文2014(夫妻感情破裂)
2014/12/14 职场文书
暂住证明怎么写
2015/06/19 职场文书
教你如何使用Python实现二叉树结构及三种遍历
2021/06/18 Python
Java基础-封装和继承
2021/07/02 Java/Android
基于Python编写简易版的天天跑酷游戏的示例代码
2022/03/23 Python
Vue Mint UI mt-swipe的使用方式
2022/06/05 Vue.js