博客園的markdown是屎!! 你可以選擇去簡書閱讀:https://www.jianshu.com/p/537156a52250
這周我們繼續這個系列,這是最后一篇。建議先閱讀前兩篇文章。
其實,我以前一直按照第二篇文章所介紹的方式寫用例,寫過UI自動化(200+用例),也寫接口自動化用例(500+用例),接口自動化第一版是用PHP寫的,當時還沒用到參數化,第二版用python重寫才用到了parameterized做參數化,結果大大縮減了測試代碼的行數。我不認為把接口參數寫到用例里有什么不妥。因為接口測試有數據的初始化動作,所以,接口用例很穩定,只要用例失敗一准是接口處理邏輯變動了,接口自動化項目被我維護了兩年,直到后來離職。之所以說這些,只是想說明我的觀點至少不是寫兩個demo總結出來的。
直到最近,我在亞馬遜上看到一本書《Selenium Framework Design in Data Driven Testing》,評價挺高,經過一翻查找,有同學將這本書第十章的例子放到了GitHub上。
https://github.com/PacktPublishing/Selenium-Framework-Design-in-Data-Driven-Testing
整本書基於Java語言,基於TestNG單元測試框架的DataProvider來實現讀JSON數據文件。所以,讀數據文件是不能脫離單元測試框討論的,因為它確實解決了用代碼寫測試用例的大部分問題。
既然這樣,那python下面的單元測試框架unittest/pytest是否也有類似的操作,不用那么麻煩就可以把文件中的數據讀出來並參數化到測試用例中。
同樣以登錄功能為例,這里將介紹支持unittest的ddt庫。
首先創建一個數據文件:test_ddt_file.json
{
"test_login_01":{
"username":"",
"password":"123",
"assert_text": "請輸入帳號"
},
"test_login_02":{
"username":"user",
"password":"",
"assert_text": "請輸入密碼"
},
"test_login_03":{
"username":"error",
"password":"error",
"assert_text": "帳號或密碼錯誤"
},
"test_login_04":{
"username":"admin",
"password":"admin123456",
"assert_text": "admin你好"
}
}
創建測試用例:
import unittest
from selenium import webdriver
from ddt import ddt, file_data
from time import sleep
@ddt
class TestLogin(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.driver = webdriver.Chrome()
cls.url = "http://127.0.0.1:8000/"
cls.driver.implicitly_wait(10)
@classmethod
def tearDownClass(cls):
cls.driver.quit()
def user_login(self, username, password):
driver = self.driver
driver.get(self.url)
driver.find_element_by_id("inputUsername").send_keys(username)
driver.find_element_by_id("inputPassword").send_keys(password)
driver.find_element_by_id("Login").click()
@file_data("./test_ddt_file.json")
def test_login(self, username, password, assert_text):
self.user_login(username, password)
if username == "admin":
sleep(2)
tips = self.driver.find_element_by_id("user").text
self.assertEqual(tips, assert_text)
else:
tips = self.driver.find_element_by_id("tips").text
self.assertEqual(tips, assert_text)
if __name__ == '__main__':
unittest.main()
注意看文件的讀取,只需要通過@file_data裝飾器指定數據文件的路徑就好。只能方便到這種程度了。那么這是不是就是完美的了?
首先,一個測試文件只能放一種類型的數據。
"test_one": [1, 2, 3],
"test_two": "split",
"test_three": {"three": 3},
"test_four": {"four": 4, "five": 5}
上面這種格式的數據肯定是不行的,因它們的數據格式是不一致。所以,我們要分四個文件分別存放這四條用例數據。
難道要自動化的項目只有登錄么?肯定不是,不同的功能點用到的數據是不一樣的。
- 1、搜索功能:名稱
- 2、添加地址功能:名稱、地址、人數、日期
- 3、簽到功能:手機號
- 4、添加嘉賓功能:姓名、手機號、郵箱
- 5、.....
你需要為每一個涉及到數據的功能點創建一個數據文件。如果系統有50個這樣的功能呢!需要創建50個數據文件。當需要維護用例的時候,你需要分兩步,第一步先找到用例代碼,然后,再根據名稱找到對應的數據文件增加或刪除一條用例,再切會到用例代碼使其運行通過...
……
@data(["", "123", "請輸入帳號"],
["user", "", "請輸入密碼"],
["error", "error", "帳號或密碼錯誤"],
["admin", "admin123456", "admin你好"],
)
def test_login_2(self, username, password, assert_text):
self.user_login(username, password)
if username == "admin":
sleep(2)
tips = self.driver.find_element_by_id("user").text
self.assertEqual(tips, assert_text)
else:
tips = self.driver.find_element_by_id("tips").text
self.assertEqual(tips, assert_text)
……
為何不把數據和用例綁定在一起,這樣不管是改用例,還是改數據都是一目了然的事情。
> 你可能會站出來說,可是用數據文件管理數據,不懂代碼也可以寫做自動化用例,你連代碼都不想看懂的人還想做自動化測試?梁靜茹給你的“勇氣”?
> 你又接着說,如果有一萬條數據,不能都把這些數據寫代碼里對吧!可拉倒吧,一萬條數據確定是功能功能轉過來的自動化用例?能舉例出你所測試的哪個功能是需要手功執行一萬條數據的么?不能!就別YY這種需求了。你怕不是和性能測試數據搞混了吧!?
> 你又說,如果一條數據很長呢?比如測試文本框的最大字符限制(500或20000),這500個字都寫代碼里肯定不優雅。好吧!你能舉的也就這么個例子了。其實,500字放到數據文件里也優化不到哪兒去。為何不寫個for循環生成500個字呢?20000個也是秒秒鍾的事呀!
本文寫作的是帶有一些個人情緒在里面的,因為我看到那些上來就教測試新手讀取excel文件的,甚至把用例都寫到excel文件的行為是不認同的。
這玩意,你做的有QTP專業么?QTP的份額還不是在下滑。開源的 robot Framework已經封裝的那么好了,過了那個風口,現在還不是不溫不火。因為業務場景是復雜多變的,前端開發技術的更新,也會倒逼自動化技術的演變。不然,功能測試人員早被自動化測試取代了。
要想把自動化技術做好,好老老實實的鍛煉自己的編程技術,從設計模式,代碼架構,方法封裝幾個方面把你的自動化化測試項目做的足夠靈活和可維護。
別整天跟風,看到別的測試人員隨便封裝了所謂的“測試框架”,你就好奇心爆棚的學兩下,寫兩個demo,然后就丟一邊了。
難道不應該潛下心好好分析自己測試的業務,哪些適合做UI,哪些適合做接口,哪些適合寫一些腳本,或做一個系統來提高測試效率。
上一篇文章有人說,我作為一個公眾號不應該用“鄙視”這樣不友善的詞,那這里聲明一個,蟲師所有文章僅代表他個人觀點,你們不認同可以噴他,與“測試圈TC”公眾號無關。