1. Never use Selenium FIT mode
Selenium分為兩種運(yùn)行模式,Driven Mode(現(xiàn)在叫Selenium Remote Control)和FIT Mode(現(xiàn)在叫Selenium Core)。
FIT Mode顧名思義,就是類似FIT Testing Framework那種使用方式,主要用于QA等非技術(shù)人員編寫Web應(yīng)用的功能測(cè)試。FIT Mode的Selenium測(cè)試使用HTML來(lái)組織測(cè)試用例。例如我要測(cè)試一個(gè)web應(yīng)用的登陸功能。我可能寫出這樣的HTML 表格。
?1
<
table
>
?2
<
tr
>
?3
?
<
td
>
open
</
td
>
?4
????????
<
td
>
http://localhost:8080/login
</
td
>
?5
????????
<
td
></
td
>
?6
</
tr
>
?7
<
tr
>
?8
?
<
td
>
type
</
td
>
?9
????????
<
td
>
id=username
</
td
>
10
????????
<
td
>
someuser
</
td
>
11
</
tr
>
12
<
tr
>
13
?
<
td
>
type
</
td
>
14
????????
<
td
>
id=password
</
td
>
15
????????
<
td
>
password
</
td
>
16
</
tr
>
17
<
tr
>
18
?
<
td
>
click
</
td
>
19
????????
<
td
>
id=login_button
</
td
>
20
????????
<
td
></
td
>
21
</
tr
>
22
<
tr
>
23
?
<
td
>
assertTextPresent
</
td
>
24
????????
<
td
>
Welcome?to?xxxx
</
td
>
25
????????
<
td
></
td
>
26
</
tr
>
27
</
table
>
不同于FIT,Selenium內(nèi)置了一系列的命令,如上例中的open, type, click以及assertTextPresent,因此QA可以完全拋開DEV獨(dú)立地編寫測(cè)試(FIT需要DEV提供Behavior Fixture)。因此FIT Mode是相當(dāng)容易使用的,哪怕不會(huì)使用HTML的QA,也可以使用FrontPage畫出三列表格,依次填入數(shù)據(jù)。
然而對(duì)于大多數(shù)team而言——尤其是敏捷team,F(xiàn)IT Mode平易的外表下是令人恐懼的泥沼。大多數(shù)團(tuán)隊(duì)往往選擇使用Selenium作為功能測(cè)試和集成測(cè)試工具而不僅僅是QA測(cè)試工具,在不同的迭代間遇到功能流程或UI變化時(shí),必須要重構(gòu)Selenium測(cè)試,或者說(shuō),F(xiàn)unctional Test Migration。令人遺憾的是,HTML based的Selenium FIT Testing的重構(gòu)竟然令人難以置信的困難。我們可以使用include等Selenium FIT擴(kuò)展,使得它可以重用詳細(xì)的功能(Log in, Log out諸如此類)。即便如此,在一個(gè)真實(shí)的項(xiàng)目中,Selenium Test的數(shù)量往往在200-500之間(我目前所處的項(xiàng)目在改用Driven Mode前已達(dá)350+),對(duì)于這么大基數(shù)的Selenium測(cè)試,手工重構(gòu)幾乎是不可想象的,而目前尚沒(méi)有HTML代碼重構(gòu)工具。即便存在泛泛意義上的HTML重構(gòu)工具,對(duì)于Selenium測(cè)試重構(gòu)的有效性尚待商榷。而使用Driven Mode上述代碼可以寫為:
1
public
?
void
?testShouldShowAWeclomeMessageAfterUserLoggedIn()?
{
2
????selenium.open(
"
http://localhost:8080/login
"
);
3
????selenium.type(
"
id=username
"
,
"
someuser
"
);
4
????selenium.type(
"
id=password
"
,?
"
password
"
);
5
????selenium.click(
"
id=login_button
"
);
6
????assertTrue(selenium.isTextPresent(
"
Welcome?to?xxxx
"
));
7
}
很自然,一個(gè)訓(xùn)練有素的程序員會(huì)重構(gòu)出如下代碼:
?1
public
?
void
?login(String?username,?String?password)?
{
?2
????selenium.open(
"
http://localhost:8080/login
"
);
?3
????selenium.type(
"
id=username
"
,username);
?4
????selenium.type(
"
id=password
"
,?password);
?5
????selenium.click(
"
id=login_button
"
);?
?6
}
?7
?8
public
?
void
?testShouldShowAWeclomeMessageAfterUserLoggedIn()?
{
?9
????login(
"
someuser
"
,?
"
password
"
);
10
????assertTrue(selenium.isTextPresent(
"
Welcome?to?xxxx
"
));
11
}
之后無(wú)論是pull up到公共基類還是extact到Utils class都是很容易的事情。由于Java在代碼重構(gòu)上便利,Java Selenium Remote Control成為使用Selenium的最佳方式。在這一點(diǎn)上,縱使Ruby語(yǔ)法上比Java簡(jiǎn)單靈活得多,它仍不是編寫Selenium測(cè)試的最佳載體(當(dāng)然一個(gè)經(jīng)過(guò)精心設(shè)計(jì)的ruby selenium dsl wrapper還是具有非凡的價(jià)值的,這個(gè)我們后面會(huì)涉及到)。
2. Using the name user, system, page instead of selenium
觀察上面提到的代碼,其中使用selenium來(lái)操縱web應(yīng)用的行為,這在Remote Control里是常見的做法,但是仍然不夠好,我們可以做一些小的變化以得到更好的測(cè)試:
?1
protected
?
void
?setup()?
{
?2
????selenium?
=
?
?
//
?intialize?selenium?instance
?3
????user?
=
?selenium;
?4
????currentPage?
=
?selenium;
?5
}
?6
?7
public
?
void
?login(String?username,?String?password)?
{
?8
????user.open(
"
http://localhost:8080/login
"
);
?9
????user.type(
"
id=username
"
,username);
10
????user.type(
"
id=password
"
,?password);
11
????user.click(
"
id=login_button
"
);?
12
}
13
14
public
?
void
?testShouldShowAWeclomeMessageAfterUserLoggedIn()?
{
15
????login(
"
some?guy
"
,?
"
password
"
);
16
????assertTrue(currentPage.isTextPresent(
"
Welcome?to?xxxx
"
));
17
}
基本上這只不過(guò)是"另一種寫法"而已,但是它更好的表達(dá)了"用戶的行為",如login代碼所示。以及"系統(tǒng)的正確相應(yīng)",即currentPage.isTextPresent()。這種是典型的對(duì)編譯器無(wú)意義對(duì)人有意義的代碼,也就是普遍意義上好的代碼。
3. Creating a DSL base on your test codes
懂得HTML的QA可以在沒(méi)有DEV的幫助下使用Selenium FIT mode,然而卻不能在沒(méi)有DEV的幫助下使用Driven Mode。于是最自然也是最fashion的做法,就是在已有的test codes之上提供Testing DSL或者Scripting Language,讓FIT mode變得更加FIT。這方面內(nèi)容是一個(gè)更大的主題,以后再詳細(xì)展開吧。
4. Hacking Selenium Object to support FIT command
Selenium FIT mode和RC mode下的命令有些許差異,比如FIT中的assertTextPresent,在RC中變成了isTextPresent。同樣還有FIT中最實(shí)用的命令clickAndWait,在RC中變成了click和waitForPageToLoad。在RC中使用FIT mode中的命令也非難事,找到com.thoughtworks.selenium.Selenium,添加方法:
public
?
void
?doCommand(String?commmand,?String
?parameters);
然后在com.thoughtworks.selenium.DefaultSelenium中添加實(shí)現(xiàn):
1
public
?
void
?doCommand(String?commmand,?String
?parameters)?
{
2
???String[]?paras?
=
?
new
?String[]
{
""
,
""
,
""
}
3
???
for
?(
int
?i?
=
?
0
;?i?
<
?parameters.length?
&&
?i?
<
?
3
;?i
++
)
4
??????paras[i]?
=
?parameters[i];
5
???commandProcessor.doCommand(command,?paras);
6
}
然后試驗(yàn)一下:
selenium.doCommand(
"
clickAndWait
"
);
在我們使用純RC mode之前曾經(jīng)用過(guò)一段中間方案,將rc code轉(zhuǎn)化為fit code來(lái)跑(因?yàn)閞c不支持https),由于不是真正的rc mode,像isTextPresent之類的方法都沒(méi)有辦法使用,只能使用FIT mode command。因此如果因?yàn)橐恍┨厥獾脑?https, chrome起不來(lái),hta bug多等等),你沒(méi)有辦法使用RC mode,但是有希望得到RC可重構(gòu)的好處,那么這個(gè)tricky的技巧倒是不錯(cuò)的選擇。
5. Using chrome and IE hta lanucher to support https
6. Run test using different browser lanucher to test browser compatibility
這兩個(gè)都是和browser lanucher相關(guān)的,Selenium和JWebUnit最大的不同在于它使用真實(shí)的瀏覽器來(lái)跑測(cè)試,從而可以更加真實(shí)地考察系統(tǒng)在不同瀏覽器中的表現(xiàn)。因此使用不同的瀏覽器lanucher來(lái)運(yùn)行測(cè)試,可以更好測(cè)試應(yīng)用的瀏覽器兼容性,這對(duì)于web 2.0應(yīng)用而言是很有幫助的。此外,使用rc提供的試驗(yàn)性lanucher,chrome和hta可以解決跨domain測(cè)試和https的問(wèn)題。不過(guò)目前hta還是有很多bug的,推薦使用chrome。當(dāng)然,最希望的還是澳洲的同事可以早日在selenium里提供https支持。