我們從一個最簡單的登錄例子開始。
最開始我們需要驗證在用戶名和密碼都正確的情況下,能夠正常登錄系統,我們這樣編寫測試代碼(以下都是偽代碼,使用TestNG和Selenium):
@Test
def should_login_success_with_exist_username_and_correct_password(){
LoginPage page = user.open(LoginPage,"/login.html")
user.perform("login",['user1','1234'],on(page))
assert page.successLogin
}
恩,很不錯,運行一下,出現紅條。為什么呢?原來測試數據庫里沒有用戶名為user1的用戶,好吧,寫個數據庫數據初始化腳本。再運行,OK,綠條!
那么,接下來我們再增加一個測試,需要覆蓋密碼錯誤時不能登錄系統的情況,很快測試就完成了:
@Test
def should_login_success_with_exist_username_and_incorrect_password(){
LoginPage page = user.open(LoginPage,"/login.html")
user.perform("login",['user1','4321'],on(page))
assert page.successLogin,false
}
再運行一下測試,綠條。好啦,現在可以看下這段代碼,恩,有些重復,重構一下:
@Test
def should_login_success_with_exist_username_and_correct_password(){
assert login('user1','1234')
}
@Test
def should_login_success_with_exist_username_and_incorrect_password(){
assert login('user1','4321'),false
}
def login(username,password){
LoginPage page = user.open(LoginPage,"/login.html")
user.perform("login",[username,password],on(page))
return page.successLogin
}
重構完成,可以看到,我們的測試方法里現在沒有了任何行為,僅僅是數據!這樣讓我感覺有點怪,不管了,先用TestNG提供的@dataProvider整理一下:
@Test(dataProvider="testdata")
def testLogin(username,password,expected){
LoginPage page = user.open(LoginPage,"/login.html")
user.perform("login",[username,password],on(page))
assert page.successLogin,expected
}
@DataProvider(name="testdata")
def Object[][] dataForLogin(){
def data=new Object[2][]
data[0]=['user1','1234',true] as Object[]
data[1]=['user1','4321',false] as Object[]
}
測試方法只剩下了一個!如果要測試不存在的用戶不能登錄系統呢?很簡單,增加數據即可!
@DataProvider(name="testdata")
def Object[][] dataForLogin(){
def data=new Object[2][]
data[0]=['user1','1234',true] as Object[]
data[1]=['user1','4321',false] as Object[]
data[1]=['inexistuser','1234',false] as Object[]
}
在我們的測試方法里,測試數據和測試的行為進行了完全的分離。從系統的功能來說,功能一旦實現,那么就是一個黑盒,我們只要提供數據即可進行測試,這個數據包括兩部分:輸入和期待的輸出。我開始暗自嘀咕:難道我以前那么多的洋洋得意測試方法很多都是不需要的嗎?這些方式為什么會存在呢?恩,想起來了,這些方法是為了覆蓋功能的各個路徑的,是提高測試覆蓋率的。那么為什么會產生這么多的測試方法呢?哦,在這些測試方法里,測試數據和測試行為是耦合在一起的!
我伸了個懶腰,突然想,這下好了,我已經封裝好了功能行為,QA想增加測試用例只需要自己增加數據就可以了,嘿嘿,爽啊。說曹操,QA到。QA mm說,你的某個功能實現有問題。我瞅了一眼,說,不可能啊(這是dev面對bug的第一反應),俺有測試的,持續集成一直是綠條的。QA mm說,在你的開發環境下測試是沒有問題的,但是在QA環境,因為數據庫變了,數據變了,應用服務器變了,所以會有些問題。我極不情愿的登錄到QA環境,一測試,還真是,郁悶。
怎么辦?修復完BUG,第一反應就是自動化測試能不能跑在QA環境呢?一般情況下,這些測試需要干凈的測試環境,我們會制造很多的測試數據,可是在QA環境下,QA有她自己的測試數據,這些數據都不存在了哈。恩,看看剛才的測試代碼,哈,就用QA的數據也可以啊,心情愉悅的改下:
@DataProvider(name="testdata")
def Object[][] dataForLogin(){
def data=new Object[2][]
data[0]=['hrong','1234',true] as Object[]
data[1]=['hrong','4321',false] as Object[]
data[1]=['rhao','1234',false] as Object[]
}
OK,完成!為了該測試既能在開發測試環境運行又能在QA環境下運行,我們可以引入一個環境變量,將測試數據扔到文件里,通過環境變量來加載不同的測試數據(測試文件)。
好吧,喝點東西(甲流很厲害,喝板藍根好了),總結一下:
數據驅動測試:
測試數據與測試行為分離,通過數據來驅動測試。
好處:
在對測試行為封裝好的情況下,QA mm能夠自己通過數據修改自動化測試;
自動化測試能夠運行在多個環境下(開發環境、QA環境、產品環境)
測試的可讀性
測試方法大量壓縮
適用范圍:
功能測試(selenium測試)
通過環境準備測試數據(非測試用例自己準備數據)
可能存在的問題:
比一般的測試編寫困難,特別是在靜態語言里
最后:該文章的思考來自于徐昊在團隊內部的相應Session.
http://www.tkk7.com/ronghao 榮浩原創,轉載請注明出處:)
posted on 2010-01-17 12:08
ronghao 閱讀(2578)
評論(0) 編輯 收藏 所屬分類:
工作日志