天天看點

在JUnit中多個testCase隻執行一次setup和tearDown的方法

每個testCase都需要使用某一種初始化比較耗時的對象(資源),舉例如資料庫連接配接、Spring Context。我們遇到的問題是Selenium測試中開啟和關閉浏覽器,如果一個test啟動關閉(我們的程式還需要登入和登出),這樣測試的時間會拖的很長,給持續內建帶來了困難。

是以,我們需要在每組不會沖突的test中間共享一個浏覽器視窗,這樣也就需要一個全局的setUp和tearDown。問題是JUnit 3.8.1裡面的setUp和tearDown是在每個test之前和之後運作的,如果在裡面初始化和關閉浏覽器就會造成上面所說的問題。要解決它,就産生了如下3種思路:

1、更新,使用JUnit4

JUnit4從TestNG裡面吸取了兩個注釋:@BeforeClass和@AfterClass

用它們注釋過的方法就會隻初始化一次,完全符合我們的需求。

Java代碼

在JUnit中多個testCase隻執行一次setup和tearDown的方法
在JUnit中多個testCase隻執行一次setup和tearDown的方法
在JUnit中多個testCase隻執行一次setup和tearDown的方法
  1. public class SeleniumTestCase extends SeleneseTestCase4 {   
  2.     protected static final Log log = LogFactory.getLog(SeleniumTestCase.class);   
  3.     protected static Selenium selenium = null;   
  4.     @BeforeClass  
  5.     public static void startSelenium() throws Exception {   
  6.         log.debug("Starting Selenium");   
  7.         selenium = SeleniumSession.getCurrentSession().getSelenium();   
  8.     }   
  9.     @AfterClass  
  10.     public static void stopSelenium() throws Exception {   
  11.         log.debug("Stoping Selenium");   
  12.         selenium.stop();   
  13.     }   
  14. }  
public class SeleniumTestCase extends SeleneseTestCase4 {

    protected static final Log log = LogFactory.getLog(SeleniumTestCase.class);
    protected static Selenium selenium = null;

    /** *//**
     * 包含了登入的代碼,保證在一個測試内部隻執行一次開啟浏覽器并登入操作
     * @throws Exception
     */
    @BeforeClass
    public static void startSelenium() throws Exception {
        log.debug("Starting Selenium");
        selenium = SeleniumSession.getCurrentSession().getSelenium();
    }

    /** *//**
     * 在該類包含的所有測試結束之後關閉浏覽器
     * @throws Exception
     */
    @AfterClass
    public static void stopSelenium() throws Exception {
        log.debug("Stoping Selenium");
        selenium.stop();
    }
}
           

這個裡面的selenium = SeleniumSession.getCurrentSession().getSelenium();其實是個singleton,第一次open new,後來就直接傳回selenium的instance(具體參考其它文章)。

這樣做非常舒服,因為完全不是Trick,而是新的feature,用起來踏實。這樣,這個類的所有@Test就會公用一個selenium打開的浏覽器了。

那麼缺點是什麼呢?缺點是放到CI環境的時候如果使用我們習慣的Ant寫執行腳本的話必須将Ant更新到1.7Beta3,因為Ant 1.6.5的Junit task不支援JUnit4……當然更新并不會帶來代碼的變化,但是問題在于Ant 1.7還是Beta,而且JUnit4需要JDK5的Annotation,你的PM估計要撇嘴了

2、JVM級别鈎子法

因為JVM支援關閉時執行制定代碼的鈎子,而static代碼會在類初始化時執行,再加上Ant調用的是類似指令行的java指令,實際上每一個測試運作在一個完整的JVM啟動關閉周期裡面,是以也就産生了這種解決方案。

Java代碼

在JUnit中多個testCase隻執行一次setup和tearDown的方法
在JUnit中多個testCase隻執行一次setup和tearDown的方法
在JUnit中多個testCase隻執行一次setup和tearDown的方法
  1. public abstract class SomeTestCase extends TestCase {   
  2.   static {   
  3.     // perform the "global" set up logic   
  4.     //這裡的代碼會在類初始化時執行,是以相當于BeforeClass   
  5.     log.debug("Starting Selenium");   
  6.         selenium = SeleniumSession.getCurrentSession().getSelenium();   
  7.     // and now register the shutdown hook for tear down logic   
  8.     //将一個匿名方法寫到這裡,就相當于AfterClass   
  9.     Runtime.getRuntime().addShutdownHook(   
  10.        new Thread(){   
  11.            public void run() {   
  12.              log.debug("Stoping Selenium");   
  13.              selenium.stop();   
  14.            }   
  15.        }   
  16.      );   
  17.   }   
  18. }  
public abstract class SomeTestCase extends TestCase {

  static {
    // perform the "global" set up logic
    //這裡的代碼會在類初始化時執行,是以相當于BeforeClass
    log.debug("Starting Selenium");
        selenium = SeleniumSession.getCurrentSession().getSelenium();

    // and now register the shutdown hook for tear down logic
    //将一個匿名方法寫到這裡,就相當于AfterClass
    Runtime.getRuntime().addShutdownHook(
       new Thread(){
           public void run() {
             log.debug("Stoping Selenium");
             selenium.stop();
           }
       }
     );
  }

}
           

3、還有别的方法,這個來自Selenium網站,似乎是不錯的中庸方案。

Java代碼

在JUnit中多個testCase隻執行一次setup和tearDown的方法
在JUnit中多個testCase隻執行一次setup和tearDown的方法
在JUnit中多個testCase隻執行一次setup和tearDown的方法
  1. import junit.framework.*;   
  2. import junit.extensions.TestSetup;   
  3. public class AllTestsOneTimeSetup {   
  4.     public static Test suite() {   
  5.         TestSuite suite = new TestSuite();   
  6.         suite.addTest(SomeTest.suite());   
  7.         suite.addTest(AnotherTest.suite());   
  8.         TestSetup wrapper = new TestSetup(suite) {   
  9.             protected void setUp() {   
  10.                 oneTimeSetUp();   
  11.             }   
  12.             protected void tearDown() {   
  13.                 oneTimeTearDown();   
  14.             }   
  15.         };   
  16.         return wrapper;   
  17.     }   
  18.     public static void oneTimeSetUp() {   
  19.         // one-time initialization code   
  20.     }   
  21.     public static void oneTimeTearDown() {   
  22.         // one-time cleanup code   
  23.     }   
  24. }  
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
    }
}
           

這個好像是比較正統的方案,不好意思我并沒有試驗,但是看起來這的确可能是限定用JDK 1.4或JUnit 3.8.1的最佳解決方案。歡迎嘗試。相關的連接配接參考這裡:http://www.cs.wm.edu/~noonan/junit/doc/faq/faq.htm#organize_3

轉自 :http://www.blogjava.net/iamtin/archive/2006/11/17/81802.html