最近接手商城的项目, 针对后台测试, 功能比较简单, 但是流程比较繁多, 涉及到前后台的交叉测试在对整个项目进行第一轮测试完成之后, 考虑以后回归测试任务比较重, 为了减轻回归测试的工作量, 所以考虑后台可以进行部分自动化测试
之前一个项目使用 robotframework 进行回归测试, 了解了 python 语言, 所以这次就使用 python+selenium 进行自动化回归测试了
配置环境
python2.7
运行工具 pycharm2017
流程说明
登录操作步骤说明
打开登录 url, 如 http://192.168.10.6/login
在用户名输入框中输入登录的用户名, 如 test001
在密码是输入框中输入密码, 如 testgood001
点击登录页面的登录按钮,
登录成功页面, 断言登录成功
线性操作
根据上面的步骤提示下面代码显示登录操作, 如下
#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()
# 打开 url
self.driver.get("http://192.168.10.6/login")
# 登录操作
def test_login(self):
title = self.driver.title
print title
now_url = self.driver.current_url
print now_url
username = "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').text
login_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 driver
if __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_name
driver.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_url
self.driver = selenium_driver
self.timeout = 30
self.parent = parent
def _open(self, url):
url = self.base_url + url
self.driver.get(url)
assert self.on_page(), 'Did not land on %s' % url
def 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.loc
loc = 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 sleep
class 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).text
username = self.find_element(*self.login_user_success_loc).text
username = 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" + character
self.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