每個testCase都需要使用某一種初始化比較耗時的對象(資源),舉例如數(shù)據(jù)庫連接、Spring Context。我們遇到的問題是Selenium測試中開啟和關(guān)閉瀏覽器,如果一個test啟動關(guān)閉(我們的程序還需要登錄和注銷),這樣測試的時間會拖的很長,給持續(xù)集成帶來了困難。
所以,我們需要在每組不會沖突的test中間共享一個瀏覽器窗口,這樣也需要一個全局的setUp和tearDown。問題是JUnit 3.8.1里面的setUp和tearDown是在每個test之前和之后運(yùn)行的,如果在里面初始化和關(guān)閉瀏覽器會造成上面所說的問題。要解決它,產(chǎn)生了如下3種思路:
1、升級,使用JUnit4
JUnit4從TestNG里面吸取了兩個注釋:@BeforeClass和@AfterClass
用它們注釋過的方法會只初始化一次,完全符合我們的需求。
public class SeleniumTestCase extends SeleneseTestCase4 {
protected static final Log log = LogFactory.getLog(SeleniumTestCase.class);
protected static Selenium selenium = null;
/** *//**
* 包含了登錄的代碼,保證在一個測試內(nèi)部只執(zhí)行一次開啟瀏覽器并登錄操作
* @throws Exception
*/
@BeforeClass
public static void startSelenium() throws Exception {
log.debug("Starting Selenium");
selenium = SeleniumSession.getCurrentSession().getSelenium();
}
/** *//**
* 在該類包含的所有測試結(jié)束之后關(guān)閉瀏覽器
* @throws Exception
*/
@AfterClass
public static void stopSelenium() throws Exception {
log.debug("Stoping Selenium");
selenium.stop();
}
}
這個里面的selenium = SeleniumSession.getCurrentSession().getSelenium();其實(shí)是個singleton,第一次open new,后來直接返回selenium的instance(具體參考其它文章)。
這樣做非常舒服,因為完全不是Trick,而是新的feature,用起來踏實(shí)。這樣,這個類的所有@Test會公用一個selenium打開的瀏覽器了。
那么缺點(diǎn)是什么呢?缺點(diǎn)是放到CI環(huán)境的時候如果使用我們習(xí)慣的Ant寫執(zhí)行腳本的話必須將Ant升級到1.7Beta3,因為Ant 1.6.5的Junit task不支持JUnit4……當(dāng)然升級并不會帶來代碼的變化,但是問題在于Ant 1.7還是Beta,而且JUnit4需要JDK5的Annotation,你的PM估計要撇嘴了
2、JVM級別鉤子法
因為JVM支持關(guān)閉時執(zhí)行制定代碼的鉤子,而static代碼會在類初始化時執(zhí)行,再加上Ant調(diào)用的是類似命令行的java命令,實(shí)際上每一個測試運(yùn)行在一個完整的JVM啟動關(guān)閉周期里面,所以也產(chǎn)生了這種解決方案。
public abstract class SomeTestCase extends TestCase {
static {
// perform. the "global" set up logic
//這里的代碼會在類初始化時執(zhí)行,所以相當(dāng)于BeforeClass
log.debug("Starting Selenium");
selenium = SeleniumSession.getCurrentSession().getSelenium();
// and now register the shutdown hook for tear down logic
//將一個匿名方法寫到這里,相當(dāng)于AfterClass
Runtime.getRuntime().addShutdownHook(
new Thread(){
public void run() {
log.debug("Stoping Selenium");
selenium.stop();
}
}
);
}
}
3、還有別的方法,這個來自Selenium網(wǎng)站,似乎是不錯的中庸方案。
JAVA代碼:
import junit.framework.*;
import junit.extensions.TestSetup;
public class AllTestsOneTimeSetup {
public static Test suite() {
TestSuite suite = new TestSuite();
suite.addTest(SomeTest.suite());
suite.addTest(AnotherTest.suite());
TestSetup wrapper = new TestSetup(suite) {
protected void setUp() {
oneTimeSetUp();
}
protected void tearDown() {
oneTimeTearDown();
}
};
return wrapper;
}
public static void oneTimeSetUp() {
// one-time initialization code
}
public static void oneTimeTearDown() {
// one-time cleanup code
}
}
這個好像是比較正統(tǒng)的方案,不好意思我并沒有試驗,但是看起來這的確可能是限定用JDK 1.4或JUnit 3.8.1的佳解決方案。歡迎嘗試。相關(guān)的連接參考這里:http://www.cs.wm.edu/~noonan/junit/doc/faq/faq.htm#organize_3