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將測試截圖保存到.\report\image\目錄中
注:運行代碼沒有錯,但是卻無法獲得截圖保存路徑?????(望知道原因的留言指點)
編寫Page Object
首先創建基礎類:E:\python\mztestpro\bbs\test_case\page_obj\base.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:\python\mztestpro\bbs\test_case\page_obj\loginPage.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:\python\mztestpro\bbs\test_case\login_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
