python3+selenium自动化测试框架详解
作者:laozhang 发布时间:2022-01-29 18:26:01
背景
为了更好的发展自身的测试技能,应对测试行业以及互联网行业的迭代变化。自学python以及自动化测试。
虽然在2017年已经开始接触了selenium,期间是断断续续执行自动化测试,因为还有其他测试任务,培训任务要执行…
前期建议大家能够学习python基本语法(python基础教程)
任务
搭建自动化测试框架,并能有效方便的进行测试,维护成本也要考虑其中。
过程
我的自动化框架可能不成熟,因为是自学的。请多包涵。也请大佬指导~
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])
猜你喜欢
- 很神奇的一个晚上,居然在以前老同事的群里跟同事讨论起CSS的东西来了,不过很意外的还是有收获。在IE中常常会碰到如果将容器定位后,出现容器内
- 我们可以先建立一个包含文件名,文件标题的待检索文件的数据库,然后,用ADO方式来访问它,并建立记录集对象。具体代码和说明见下:
- 本文环境Python 3.6.5Django 2.0.4fix(2018.5.19):最近得知Django 的model基类需要声明为abs
- 本文实例讲述了Python 操作 PostgreSQL 数据库。分享给大家供大家参考,具体如下:我使用的是 Python 3.7.0Post
- 1.连接本机数据库 A. 本机若有静态IP,oracle安装好后,就能连接本机oracle数据库。 B. 安装oracle时,本机没有静态I
- 一个单步的动作,用了这个脚本,就可以重复执行100遍1000遍。上面就是一个路径描边100遍的效果,吼吼~ 不知道大家明白用处没有?(以前老
- 前言Martin(Bob大叔)曾在《代码整洁之道》一书打趣地说:当你的代码在做 Code Review 时,审查者要是愤怒地吼道:“What
- 本文系统的对HTTP Headers进行了简明易懂的阐述,我仅稍作笔记。什么是HTTP HeadersHTTP是“Hypertext Tra
- 此代码适合你做网站用,普通朋友可以不用理这个东西!ASP:<%dim objXMLHTTP, qq, pwd qq = &
- php开启openssl的方法,大多数情况下openssl是没有开启的,要想启用需要进行下简单的设置windows下开启方法:1: 首先检查
- ASP访问数据库的方式有哪些?在ASP中可以通过三种方式访问数据库:1、IDC(Internet Database Connec
- 1.ACCESS查询(query_info):select * from info where stu = name1 and age =
- 在ASP.net页面中,我们编写JavaScript脚本附加有注释时,这些注释也往往会随JavaScript脚本一起送到客户端。
- 减少HTTP请求,是可以提高网站速度的,把所有的背景图像都放到一个图片文件中,然后通过CSS的background-image和backgr
- 使用cookie来判断来访者身份,是否是首次登陆, asp代码实例如下:< %@ LANGUAGE=&q
- 安装npm install --save reduxnpm install --save redux-saga配置actionactionT
- 1.sp_helpsort SELECT SERVERPROPERTY ('Collation') 查看你的排序规则. 不过
- 对想要在可视化的环境下制作复杂网页的专业网页制作者来说,Dreamweaver 已经渐渐在网页编辑工具市场中展露头角,成为专业人士
- 首先添加一个splice函数:splice:该方法的作用就是从数组中删除一个元素array.splice(index,count,value
- 本文实例讲述了PHP获取二叉树镜像的方法。分享给大家供大家参考,具体如下:问题操作给定的二叉树,将其变换为源二叉树的镜像。解决思路翻转二叉树