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 获取新浪微博的最新公共微博实例分享
Jul 03 Python
Python3基础之基本数据类型概述
Aug 13 Python
详解Python的Twisted框架中reactor事件管理器的用法
May 25 Python
Python简单获取自身外网IP的方法
Sep 18 Python
示例详解Python3 or Python2 两者之间的差异
Aug 23 Python
python实现kmp算法的实例代码
Apr 03 Python
Django打印出在数据库中执行的语句问题
Jul 25 Python
numpy ndarray 取出满足特定条件的某些行实例
Dec 05 Python
Python如何使用argparse模块处理命令行参数
Dec 11 Python
python如何获取apk的packagename和activity
Jan 10 Python
利用python绘制正态分布曲线
Jan 04 Python
详解Python中的进程和线程
Jun 23 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
《星际争霸II》全新指挥官斯台特曼现已上线
2020/03/08 星际争霸
php操作mysqli(示例代码)
2013/10/28 PHP
PHP过滤器 filter_has_var() 函数用法实例分析
2020/04/23 PHP
用函数式编程技术编写优美的 JavaScript_ibm
2008/05/16 Javascript
JavaScript学习笔记记录我的旅程
2012/05/23 Javascript
jQuery循环滚动新闻列表示例代码
2014/06/17 Javascript
Jquery注册事件实现方法
2015/05/18 Javascript
解决jquery无法找到其他父级子集问题的方法
2016/05/10 Javascript
微信小程序 window_x64环境搭建
2016/09/30 Javascript
js实现碰撞检测特效代码分享
2016/10/16 Javascript
基于mpvue的简单弹窗组件mptoast使用详解
2019/08/02 Javascript
javascript实现摄像头拍照预览
2019/09/30 Javascript
vue2.0实现列表数据增加和删除
2020/06/17 Javascript
vue页面引入three.js实现3d动画场景操作
2020/08/10 Javascript
Node.JS如何实现JWT原理
2020/09/18 Javascript
Python第三方库xlrd/xlwt的安装与读写Excel表格
2017/01/21 Python
python3+PyQt5自定义视图详解
2018/04/24 Python
基于DataFrame改变列类型的方法
2018/07/25 Python
Python使用一行代码获取上个月是几月
2018/08/30 Python
对Python3中bytes和HexStr之间的转换详解
2018/12/04 Python
Django管理员账号和密码忘记的完美解决方法
2018/12/06 Python
python matplotlib实现双Y轴的实例
2019/02/12 Python
python opencv 二值化 计算白色像素点的实例
2019/07/03 Python
Python3 中作为一等对象的函数解析
2019/12/11 Python
python实现从ftp服务器下载文件
2020/03/03 Python
Django实现简单的分页功能
2021/02/22 Python
深入探究HTML5的History API
2015/07/09 HTML / CSS
Bose法国官网:购买耳机、扬声器、家庭影院、专业音响
2017/12/21 全球购物
乌克兰网上服装店:Bolf.ua
2018/10/30 全球购物
乌克兰电子产品和家用电器购物网站:TOUCH
2019/08/09 全球购物
光声世纪笔试题目
2012/08/25 面试题
销售人员个人求职信
2013/09/26 职场文书
群众路线个人整改措施
2014/10/24 职场文书
党的群众路线调研报告
2014/11/03 职场文书
公司周年庆典致辞
2015/07/30 职场文书
Java实现简单小画板
2022/06/10 Java/Android