1.一个用例为一个完整的场景,从用户登陆系统到最终退出并关闭浏览器。
2.一个用例只验证一个功能点,不要试图在用户登陆系统后把所有的功能都验证一遍。
3.尽可能少的编写逆向逻辑用例。一方面因为逆向逻辑的用例很多(例如。手机号输错有十几种情况);另外一方面自动化本身比较脆弱,复杂的逆向逻辑用例实现起来比较麻烦且容易出错。
4.用例与用例之间尽量避免产生依赖。
5.一条测试用例完成测试后需要对测试场景进行还原,以避免影响其他测试用例的执行。
driver.py
1 from selenium.webdriver import Remote 2 from selenium import webdriver 3 4 5 # 启动浏览器驱动 6 def browser(): 7 # driver = webdriver.Firefox() 8 host = '127.0.0.1:4444' # 运行主机:端口号(本机默认:127.0.0.1:4444) 9 dc = {'browserName': 'firefox'} # 指定浏览器('chrome','firefox') 10 driver = Remote(command_executor = 'http://' + host + '/wd/hub,desired_capabilities = dc') 11 return driver 12 if __name__ == '__main__': 13 dr = browser() 14 dr.get('http://www.baidu.com') 15 dr.quit()
定义浏览器驱动函数browser()该函数可以进行配置,根据我们的需求,配置测试用例在不同的主机及浏览器下运行。
2.自定义测试框架类:
1 from selenium import webdriver 2 from .driver import browser 3 import unittest 4 import os 5 6 7 class MyTest (unittest.TestCase): 8 def setUp(self): 9 self.driver = browser () 10 self.driver.implicitly_wait (10) 11 self.driver.maximize_window () 12 13 def tearDown(self): 14 self.driver.quit ()
定义MyTest()类用于继承unittest.TestCase类,因为创建的所有测试类中setUp()与tearDown()方法所做的事情相同。所以将他们抽象为MyTest()类,好处就是编写测试用例不再去考虑这两个方法的实现。
3.定义截图函数
获取路径参考:https://www.cnblogs.com/wuxie1989/p/5623435.html
from selenium import webdriver
import os
# 截图函数
def insert_img(driver, file_name):
# 获取路径名:os.path.dirname() 获取文件所在目录的完整路径:os.path.dirname(__file__)
base_dir = os.path.dirname(os.path.dirname(__file__))
print(base_dir)
base_dir = str(base_dir) # 将地址转为字符串
print(base_dir)
base_dir = base_dir.replace('/', '\')
print(base_dir)
base = base_dir.split('/test_case')[0] # 以/test_case为分隔符,取第一个分割的部分
print(base)
file_path = base + "\report\image\" + file_name
print(file_path)
driver.save_screenshot(file_path)
if __name__ == '__main__':
driver = webdriver.Firefox()
driver.get("https://www.baidu.com")
insert_img(driver, 'baidu.png')
driver.quit()
创建截图函数insert_img(),为了保持自动化项目的移植性,采用相对路径的方法hi将测试截图保存到. eportimage目录中
注:运行代码没有错,但是却无法获得截图保存路径?????(望知道原因的留言指点)
编写Page Object
首先创建基础类:E:pythonmztestprobs est_casepage_objase.py
class Page (object):
"""
页面基础类,用于所有页面的继承
"""
bbs_url = 'http://bbs.meizu.cn'
def __init__(self, selenium_driver, base_url=bbs_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 find_element(self, *loc):
return self.driver.find_element(*loc)
def open(self):
self.__open(self.url)
def on_page(self):
return self.driver.current_url == (self.base_url + self.url)
def script(self, src):
return self.driver.execute_script(src)
创建页面基础类,通过_init_()方法初始化参数:浏览器驱动,URL地址,超时时长等。定义的基本方法:open()用于打开BBS地址;find_element()和find_element()分别用来定位单个与多个
元素;创建script()方法可以更简便的调用JavaScript代码。
创建BBS登录对象类:
E:pythonmztestprobs est_casepage_objloginPage.py
1 from selenium.webdriver.common.action_chains import ActionChains 2 from selenium.webdriver.common.by import By 3 from time import sleep 4 import base 5 6 7 class login (base.Page): 8 """ 9 用户登录界面 10 """ 11 url = '/' 12 # Action 13 bbs_login_user_loc = (By.XPATH, "//div[@id='mzCust']/div/img") 14 bbs_login_button_loc = (By.ID, "mzLogin") 15 16 def bbs_login(self): 17 self.find_element (*self.bbs_login_user_loc).click () 18 sleep (3) 19 self.find_element (*self.bbs_login_button_loc).click () 20 21 login_username_loc = (By.ID, "account") 22 login_password_loc = (By.ID, "password") 23 bbs_login_button_loc = (By.ID, "login") 24 25 # 登录用户名 26 def login_username(self, username): 27 self.find_element (*self.login_username_loc).send_keys (username) 28 29 # 登录密码 30 def login_password(self, password): 31 self.find_element (*self.login_password_loc).send_keys (password) 32 33 # 登录按钮 34 def login_button(self): 35 self.find_element (*self.login_password_loc).click () 36 37 # 定义统一登录接口 38 def user_login(self, username="username", password="111"): 39 # 获取用户名与登录密码 40 self.open () 41 self.bbs_login () 42 self.login_username (username) 43 self.login_password (password) 44 self.login_button () 45 sleep (1) 46 47 user_error_hint_loc = (By.XPATH, "//span[@for = 'account']") 48 pawd_error_hint_loc = (By.XPATH, "//span[@for = 'password']") 49 user_login_success_loc = (By.ID, "mzCustName") 50 51 # 用户名错误提示 52 def user_error_hint(self): 53 return self.find_element (*self.user_error_hint_loc).text 54 # 密码错误提示 55 56 def paw_error_hint(self): 57 return self.find_element (*self.pawd_error_hint_loc).text 58 59 # 登录成功用户名 60 def user_login_success(self): 61 return self.find_element (*self.user_login_success_loc).text 62 63 创建登录页面对象,对用户登录面上的用户名/密码输入框,登录按钮和提示信息等元素的定位进行封装。除此之外,还创建user_login()方法作为系统统一登录的入口。关于对操作步骤的封装 64 既可以放在page object当中,也可以放在测试用例当中。这主要根据具体需求来衡量。这里之所以存放在Page_object当中,主要考虑到还有其他用例会挑用到该登录方法。 65 为username和password 66 入参设置了默认值是为了方便其他测试y用例在调用user_login()时不用再传递登录用户信息,因为该系统大多用例的执行使用该账号即可,同时也方便了在这账号失效时的修改。
编写测试用例
编写测试用例时会集中精力考虑用例的设计和实现。
路径:E:pythonmztestprobs est_caselogin_sta.py
此处注意文件名的创建。例如:假设登录页的对象名为loginPage.py,那么关于测试登录的文件应该命名为login_sta.py,方便用例报错时问题的追踪。
1 import random 2 import sys 3 import unittest 4 from time import sleep 5 6 sys.path.append("./models") 7 8 import myTest 9 import function 10 from myunit import * 11 12 sys.path.append("./page_obj") 13 from loginPage import * 14 15 16 class loginTest(myunit.myTest): 17 """ 社区登录测试 """ 18 19 # 测试用户登录 20 def user_login_verify(self, username="", password=""): 21 login(self.driver).user_login(username, password) 22 23 def test_login(self): 24 """用户名、密码为空登录""" 25 self.user_login_verify() 26 po = login(self.driver) 27 self.assertEqual(po.user_error_hint(), "账号不能为空") 28 self.assertEqual(po.pawd_error_hint(), "密码不能为空") 29 function.insert_img(self.driver, "user_pawd_empty.jpg") 30 31 def test_login2(self): 32 """用户名正确,密码为空登录""" 33 self.user_login_verify(username="py1test") 34 po = login(self.driver) 35 self.assertEqual(po.pawd_error_hint(), "密码不能为空") 36 function.insert_img(self.driver, "pawd_empty.jpg") 37 38 def test_login3(self): 39 """用户名为空,密码正确""" 40 self.user_login_verify(password="abc123456") 41 po = login(self.driver) 42 self.assertEqual(po.user_error_hint(), "账号不能为空") 43 function.insert_img(self.driver, "user_empty.jpg") 44 45 def test_login4(self): 46 """用户名与密码不匹配""" 47 character = random.choice('wqwertyuiop') 48 username = "zhangsan" + character 49 self.user_login_verify(username=username, password='123456') 50 po = login(self.driver) 51 self.assertEqual(po.pawd_error_hint(), "密码与账号不匹配") 52 function.insert_img(self.drive.jpg) 53 54 def test_login5(self): 55 """用户名、密码正确""" 56 self.user_login_verify(username="zhangsan", password="123456") 57 sleep(2) 58 po = login(self.driver) 59 self.assertEqual(po.user_login_success(), "张三") 60 function.insert_img(self.driver, "user_pawd_ture.jpg") 61 62 63 if __name__ == "__main__": 64 unittest.main()
注:上面代码运行会有报错,可以引入模块换为:
import random
import sys
import unittest
from time import sleep
from test_case.page_obj.loginPage import login
from test_case.models.function import insert_img
from test_case.models.myunit import MyTest