最近接手商城的项目,针对后台测试,功能比较简单,但是流程比较繁多,涉及到前后台的交叉测试。在对整个项目进行第一轮测试完成之后,考虑以后回归测试任务比较重,为了减轻回归测试的工作量,所以考虑后台可以进行部分自动化测试。

    之前一个项目使用robotframework进行回归测试,了解了python语言,所以这次就使用python+selenium进行自动化回归测试了。

配置环境

  • python2.7
  • 运行工具pycharm2017

    流程说明

    登录操作步骤说明

  1. 打开登录url,如http://192.168.10.6/login
  2. 在用户名输入框中输入登录的用户名,如test001
  3. 在密码是输入框中输入密码,如testgood001
  4. 点击登录页面的登录按钮,
  5. 登录成功页面,断言登录成功

线性操作

根据上面的步骤提示下面代码显示登录操作,如下

#coding=utf-8
from selenium import webdriver
import unittest
import sys
reload(sys)
sys.setdefaultencoding('utf8')
class TestLogin(unittest.TestCase):
# 指定浏览器def setUp(self):self.driver = webdriver.Firefox()# 打开urlself.driver.get("http://192.168.10.6/login")# 登录操作def test_login(self):title = self.driver.titleprint titlenow_url = self.driver.current_urlprint now_urlusername = "test001"password = "testgood001"# 执行登录操作#用户名的定位self.driver.find_element_by_id("username").clear()self.driver.find_element_by_id("username").send_keys(username)#密码的定位self.driver.find_element_by_id("password").clear()self.driver.find_element_by_id("password").send_keys(password)# 点击登录self.driver.find_element_by_css_selector(".btn.btn-success.btn-block").click()# 登录成功断言login_name = self.driver.find_element_by_xpath('html/body/div[3]/div[2]/ul/li[1]/a/strong').textlogin_name = login_name.strip('您好:')assert login_name == username# 关闭浏览器def tearDown(self):self.driver.quit()if __name__ == "__main__":
unittest.main()

    上面代码显示的是登录成功的正常用例;实际操作中,针对登录不仅仅有正常用例,还有异常用例,如用户名为空,密码为空,用户名错误,密码错误等;我们不能一个用例编写一个py文件,如果这样操作从本质而言相反增加了工作量。

    既然问题出来了,那么如何解决这个问题呢?

    思路:针对登录而言,所有的步骤都是一样的,唯一不同的就是登录的用户名和密码,所以我们可以封装登录步骤,然后只需要专注不同测试用例中的登录的用户名和密码的验证即可。

    这里为了后续测试的简便,使用了selenium中的po模式,即针对每个功能的操作页面进行封装,而后在针对该页面进行测试用例的编写。如这里的登录页面,我们需要针对登录页面进行封装操作,把登录页面中的用户名、密码和登录按钮的定位进行封装,这样用例中只关注输入不同的用户名和密码进行验证即可。

说明:

    这里浏览器的打开和关闭也进行了封装,放在myunit.py中。

po模式设计

    整体设计的结构如图所示

    models/driver.py中封装了打开浏览器的操作,这里使用的火狐浏览器进行操作。代码如下

# -*-coding:utf-8-*-
# _author_ = "janehost"
from selenium.webdriver import Remote
from selenium import webdriver
import sys
# 启动浏览器
reload(sys)
sys.setdefaultencoding('utf8')
def browser():driver = webdriver.Firefox()return driverif __name__ == '__main__':dr = browser()dr.get("http://192.168.10.6/login")dr.quit()

    models/myunit.py中主要封装了浏览器的启动和关闭的操作,代码如下

# -*-coding:utf-8-*-
# _author_ = "janehost"
import unittest,sys
from selenium import webdriver
from driver import browser
reload(sys)
sys.setdefaultencoding('utf8')class MyTest(unittest.TestCase):def setUp(self):self.driver = browser()self.driver.implicitly_wait(10)self.driver.maximize_window()def tearDown(self):self.driver.quit()if __name__ == '__main__':unittest.main()

    models/function.py中主要封装了截图的操作方法,代码参考如下

# -*-coding:utf-8-*-
# _author_ = "janehost"
from selenium import webdriver
import os,sys
reload(sys)
sys.setdefaultencoding('utf8')
# 截图函数
def insert_img(driver, file_name):base_dir = os.path.dirname(os.path.dirname(__file__))base_dir = str(base_dir)base_dir = base_dir.replace('\\', '/')base = base_dir.split('test_case')[0]file_path = base + "report/image/" + file_namedriver.get_screenshot_as_file(file_path)if __name__ == '__main__':driver = webdriver.Firefox()driver.get("http://192.168.10.6/login")insert_img(driver, 'login.jpg')driver.quit()

    下面就是po模式的重点,针对页面的封装,首先创建一个page页面的基本页面,page_obj\base.py代码如下

# -*-coding:utf-8-*-
# _author_ = "janehost"from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import sys
reload(sys)
sys.setdefaultencoding('utf8')
class Page(object):'''
页面基础类,用于所有页面的继承
'''base_url = "http://192.168.10.6/login"def __init__(self, selenium_driver, base_url=base_url, parent=None):self.base_url = base_urlself.driver = selenium_driverself.timeout = 30self.parent = parentdef _open(self, url):url = self.base_url + urlself.driver.get(url)assert self.on_page(), 'Did not land on %s' % urldef open(self):self._open(self.url)def on_page(self):#return (self.driver.current_url).encode('utf-8') == (self.base_url + self.url)return self.driver.current_url.encode('utf-8') == (self.base_url + self.url)def find_element(self, *loc):# return self.driver.find_element(*loc)try:# 确保所有元素是可见的# 注意:以下入参为元组的元素,需要加*。python存在这种特性,就是将入参放在元组里。#WebDriverWait(self.driver,10).until(lambda driver: driver.find_element(*loc).is_displayed())# 注意:以下入参本身是元组,不需要加*WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located(loc))return self.driver.find_element(*loc)except:print u"%s 页面中未能找到 %s 元素"%(self, loc)def find_elements(self, *loc):return self.driver.find_elements(*loc)def script(self, src):return self.driver.execute_script(src)def swtich_frame(self, loc):return self.driver.swith_to_frame(loc)def send_keys(self, loc, value, clear_first=True, click_first=True):try:# getattr相当于self.locloc = getattr(self, "_%s" % loc)if click_first:self.find_element(*loc).click()if clear_first:self.find_element(*loc).clear()self.find_element(*loc).send_keys(value)except ArithmeticError:print u"%s 页面中未能找到 %s 元素" % (self, loc)

    登录页面元素的封装page_obj\loginPage.py,代码如下

# -*-coding:utf-8-*-
# _author_ = "janehost"
"""
思路:创建登录页面对象,对用户登录页面上的用户名/密码输入框、登录按钮和
提示信息等元素的定位进行封装。
"""
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
from base import Page
from time import sleepclass login(Page):'''用户登录界面'''url = '/'# 登录用户名的定位login_username_loc = (By.ID, 'username')# 登录密码的定位login_password_loc = (By.ID,'password')# 登录按钮的定位login_button_loc = (By.CSS_SELECTOR,'.btn.btn-success.btn-block')# 登录错误提示的定位login_error_loc = (By.ID,'error_msg')# 登录成功用户名信息login_user_success_loc = (By.XPATH, 'html/body/div[3]/div[2]/ul/li[1]/a/strong')# 登录用户名def login_username(self, username):self.find_element(*self.login_username_loc).clear()self.find_element(*self.login_username_loc).send_keys(username)# 登录密码def login_password(self, password):self.find_element(*self.login_password_loc).clear()self.find_element(*self.login_password_loc).send_keys(password)# 登录按钮def login_button(self):self.find_element(*self.login_button_loc).click()# 统一登录入口def user_login(self, username="testuser01", password="testgood001"):# 获取用户名和页面登录self.open()self.login_username(username)self.login_password(password)self.login_button()sleep(3)# 登录错误提示信息def login_error_hint(self):return self.find_element(*self.login_error_loc).text# 登录成功用户名信息def login_user_success(self):#return self.find_element(*self.login_user_success_loc).textusername = self.find_element(*self.login_user_success_loc).textusername = username.strip('您好:')return username

    登录测试用例信息test_case\login_sta.py,代码如下

# -*-coding:utf-8-*-
# _author_ = "janehost"
from time import sleep
import unittest, random, sys
from models import myunit, function
from page_obj.loginPage import login
sys.path.append("./models")
sys.path.append("./page_obj")
reload(sys)
sys.setdefaultencoding('utf8')
class loginTest(myunit.MyTest):'''测试用户登录'''def user_login_verify(self, username="", password=""):login(self.driver).user_login(username, password)def test_login1(self):'''用户名、密码为空登录'''self.user_login_verify()po = login(self.driver)self.assertEqual(po.login_error_hint(), '用户名或密码不能为空')function.insert_img(self.driver, "user_pawd_empty.jpg")def test_login2(self):'''用户名正确,密码为空登录验证'''self.user_login_verify(username="ces")po = login(self.driver)self.assertEqual(po.login_error_hint(), "用户名或密码不能为空")function.insert_img(self.driver,"pawd_empty.jpg")def test_login3(self):'''用户名为空,密码正确'''self.user_login_verify(password="12334ddf")po = login(self.driver)self.assertEqual(po.login_error_hint(),"用户名或密码不能为空")function.insert_img(self.driver, "user_empty.jpg")def test_login4(self):'''用户名和密码不匹配'''character = random.choice('abcdefghijklmnopqrstuvwxyz')username = "sdw" + characterself.user_login_verify(username=username, password="2sdfd")po = login(self.driver)self.assertEqual(po.login_error_hint(), "用户名或密码错误")function.insert_img(self.driver, "user_pass_error.jpg")def test_login5(self):'''用户名、密码正确'''self.user_login_verify(username="adtest" , password="4dscsdx")sleep(3)po = login(self.driver)self.assertEqual(po.login_user_success(), u'adtest')function.insert_img(self.driver, "user_pwd_true.jpg")if __name__ == '__main__':unittest.main()

    这样登录的测试用例就完成了。使用po模式之后,如果页面ui发生变化,我们只需要修改元素的定位方法,而不需要改动整个框架,相对而言比较快捷。

参考:

小小的博客 [http://www.cnblogs.com/xiaozhiblog/p/5378723.html]

selenium2 python自动化测试实战(虫师)

转载于:https://www.cnblogs.com/LOVEYU/p/8392269.html

selenium+python自动化测试系列(一):登录相关推荐

  1. selenium+python自动化测试系列(二):AutoIt工具实现本地文件上传

    AutoIt使用简单说明 AutoIt的安装这里就不在啰嗦,可以参考AutoIt安装或者自行搜索解决. 第一步:定位上传文件路径的文本框 这里举例说明,如何定位?如图 这里我们看到上传文件的类型是bu ...

  2. selenium + python自动化测试unittest框架学习(二)

    1.unittest单元测试框架文件结构 unittest是python单元测试框架之一,unittest测试框架的主要文件结构: File >report >all_case.py &g ...

  3. selenium +python自动化测试发QQ空间说说

    selenium +python自动化测试发QQ空间说说 import time from selenium import webdriver# 1. 打开网站,窗口最大化 driver=webdri ...

  4. selenium + python自动化测试环境搭建

    elenium 是一个web的自动化测试工具,不少学习功能自动化的同学开始首选selenium ,相因为它相比QTP有诸多有点: 免费,也不用再为破解QTP而大伤脑筋 小巧,对于不同的语言它只是一个包 ...

  5. selenium + python自动化测试unittest框架学习(五)webdriver的二次封装

    因为webdriver的api方法很长,再加上大多数的定位方式是以xpath方式定位,更加让代码看起来超级长,为了使整体的代码看起来整洁,对webdriver进行封装,学习资料来源于虫师的<se ...

  6. selenium + python自动化测试unittest框架学习(一)selenium原理及应用

    unittest框架的学习得益于虫师的<selenium+python自动化实践>这一书,该书讲得很详细,大家可以去看下,我也只学到一点点用于工作中,闲暇时记录下自己所学才能更加印象深刻. ...

  7. Appium python自动化测试系列之Capability介绍(五)

    ​5.1 Capability介绍 5.1.1 什么是Capability 在讲capability之前大家是否还记得在讲log时给大家看过的启动时的日志?在我们的整个启动日志中会出现一些配置信息,其 ...

  8. Python自动化测试系列[v1.0.0][Win32模拟键盘]

    在实际的自动化代码调试过程中,往往Selenium提供的方法不能满足于自动化任务,例如定位某个按钮要完成点击操作,定位正确但就是无法完成点击,此时如果掌握模拟键盘的方法便可以为我们的自动化提供很大的帮 ...

  9. selenium python自动化测试教程_Python selenium自动化测试模型图解

    1.线性测试 优势:每一个脚本都是完整独立的,每一个脚本对应一个测试用例 缺点:开发成本高,会有重复操作重复脚本:维护成本也高,修改重复操作的脚本时,要逐一进行修改. 2.模块化驱动测试 把重复的操作 ...

最新文章

  1. centos7 cacti php7,Centos7 cacti 使用笔记
  2. s2sh集成dataSource配置无效的问题 -Access denied for user 'sa'@'localhost'
  3. mysql binlog_format 三种格式 详解 ---摘抄
  4. ant指定servlet版本_Spring工具 - AntPathMatcherUrlPathHelper(针对URL进行处理)
  5. Java 0xffffffff隐式类型转换的坑
  6. 第三次预作业20155231邵煜楠:虚拟机上的Linux学习
  7. JavaScript 九种跨域方式实现原理 1
  8. 蚂蚁课堂-第四期-基于springcloud构建微服务电商项目_阿里巴巴29个屌炸天的开源项目,你用过几个?附编程资料!!!...
  9. Visual Studio 常用快捷键(一)
  10. 粒子滤波(PF:Particle Filter与卡尔曼滤波(Kalman Filter)相比较 (转载)
  11. java快速查找素数_Java实现快速查找某个范围内的所有素数
  12. 工程数学线性代数第六版答案与解析,《线性代数附册学习辅导与习题全解》
  13. C/C++ typedef用法
  14. 离散数学关于等价关系的证明
  15. 学习使用php实现公历农历转换的方法代码
  16. Markdown 语法大全 包括设置字体 颜色
  17. C语言中负数在计算机内部的二进制表示方式(以补码表示负数、整数的范围及所占字节数)
  18. vivo X90、vivo X90 Pro和vivo X90 Pro+的区别 参数对比哪个好
  19. Android 存储相册,Android 相册图片存储
  20. LINUX学习笔记:31个常用LINUX命令和相关解释

热门文章

  1. java线程能做什么_java中的多线程能做什么 ?基本作用能说下吗?
  2. 张小明教授+计算机,香港浸会大学、实验室兼职导师张晓明教授访问实验室并做学术报告...
  3. runtime无法执行grep_让你的 Shell 命令执行可视化和告警
  4. 因为修苹果电脑太贵,美国人自学当上百万粉博主,网友:坐标深圳,不存在这问题...
  5. AlphaGo之父对话《连线》,曾被导师劝阻研究强化学习,如今获得ACM计算奖
  6. 一年半跻身网约车业务前二,现发起首个自动驾驶联盟,T3出行是一家怎样的公司?...
  7. QTP的那些事--不能识别web上的测试对象
  8. springboot mybatis 项目框架源码 shiro 集成代码生成器 ehcache缓存
  9. RabbitMQ分布式集群架构
  10. Java动态追踪技术探究