在JUnit中多个testCase只执行一次setup和tearDown的方法
2007-01-08 14:01
381 查看
http://tin.javaeye.com/blog/35114
这个问题出现在这种情况,你的每个testCase都需要使用某一种初始化比较耗时的对象(资源),举例如数据库连接、Spring Context。我们遇到的问题是Selenium测试中开启和关闭浏览器,如果一个test启动关闭(我们的程序还需要登录和注销),这样测试的时间会 拖的很长,给持续集成带来了困难。
所以,我们需要在每组不会冲突的test中间共享一个浏览器窗口,这样也就需要一个全局的setUp和 tearDown。问题是JUnit 3.8.1里面的setUp和tearDown是在每个test之前和之后运行的,如果在里面初始化和关闭浏览器就会造成上面所说的问题。要解决它,就产 生了如下3种思路:
1、升级,使用JUnit4
JUnit4从TestNG里面吸取了两个注释:@BeforeClass和@AfterClass
用它们注释过的方法就会只初始化一次,完全符合我们的需求。
仍然有setUp/tearDown,标签为@Before/@After [winnerbao add
]
public
class
SeleniumTestCase [
extends
SeleneseTestCase4这个extends没有必要 winnerbao add
]
![](http://tin.javaeye.com/Images/dot.gif)
{
protected
static
final
Log log
=
LogFactory.getLog(SeleniumTestCase.
class
);
protected
static
Selenium selenium
=
null
;
/** */
/**
* 包含了登录的代码,保证在一个测试内部只执行一次开启浏览器并登录操作
*
@throws
Exception
*/
@BeforeClass
public
static
void
startSelenium()
throws
Exception
![](http://tin.javaeye.com/Images/dot.gif)
{
log.debug(
"
Starting Selenium
![](http://tin.javaeye.com/Images/dot.gif)
"
);
selenium
=
SeleniumSession.getCurrentSession().getSelenium();
}
/** */
/**
* 在该类包含的所有测试结束之后关闭浏览器
*
@throws
Exception
*/
@AfterClass
public
static
void
stopSelenium()
throws
Exception
![](http://tin.javaeye.com/Images/dot.gif)
{
log.debug(
"
Stoping Selenium
![](http://tin.javaeye.com/Images/dot.gif)
"
);
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估计要撇嘴
了
![](http://tin.javaeye.com/Emoticons/74_74.gif)
2、JVM级别钩子法
因为JVM支持关闭时执行制定代码的钩子,而static代码会在类初始化时执行,再加上Ant调用的是类似命令行的java命令,实际上每一个测试运行在一个完整的JVM启动关闭周期里面,所以也就产生了这种解决方案。
这个方案来自taowen同学的两则Selenium经验
。
代码我恢复了一下,大概是这样:
public
abstract
class
SomeTestCase
extends
TestCase {
static
{
//
perform the "global" set up logic
//
这里的代码会在类初始化时执行,所以相当于BeforeClass
log.debug(
"
Starting Selenium
![](http://tin.javaeye.com/Images/dot.gif)
"
);
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
![](http://tin.javaeye.com/Images/dot.gif)
"
);
selenium.stop();
}
}
);
}
}
这个方法挺酷的,我认为完全可以被称作“奇技淫巧”。缺点就是,有点不好看。
3、还有别的方法,这个来自Selenium网站,似乎是不错的中庸方案。
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
这个问题出现在这种情况,你的每个testCase都需要使用某一种初始化比较耗时的对象(资源),举例如数据库连接、Spring Context。我们遇到的问题是Selenium测试中开启和关闭浏览器,如果一个test启动关闭(我们的程序还需要登录和注销),这样测试的时间会 拖的很长,给持续集成带来了困难。
所以,我们需要在每组不会冲突的test中间共享一个浏览器窗口,这样也就需要一个全局的setUp和 tearDown。问题是JUnit 3.8.1里面的setUp和tearDown是在每个test之前和之后运行的,如果在里面初始化和关闭浏览器就会造成上面所说的问题。要解决它,就产 生了如下3种思路:
1、升级,使用JUnit4
JUnit4从TestNG里面吸取了两个注释:@BeforeClass和@AfterClass
用它们注释过的方法就会只初始化一次,完全符合我们的需求。
仍然有setUp/tearDown,标签为@Before/@After [winnerbao add
]
public
class
SeleniumTestCase [
extends
SeleneseTestCase4这个extends没有必要 winnerbao add
]
![](http://tin.javaeye.com/Images/dot.gif)
{
protected
static
final
Log log
=
LogFactory.getLog(SeleniumTestCase.
class
);
protected
static
Selenium selenium
=
null
;
/** */
/**
* 包含了登录的代码,保证在一个测试内部只执行一次开启浏览器并登录操作
*
@throws
Exception
*/
@BeforeClass
public
static
void
startSelenium()
throws
Exception
![](http://tin.javaeye.com/Images/dot.gif)
{
log.debug(
"
Starting Selenium
![](http://tin.javaeye.com/Images/dot.gif)
"
);
selenium
=
SeleniumSession.getCurrentSession().getSelenium();
}
/** */
/**
* 在该类包含的所有测试结束之后关闭浏览器
*
@throws
Exception
*/
@AfterClass
public
static
void
stopSelenium()
throws
Exception
![](http://tin.javaeye.com/Images/dot.gif)
{
log.debug(
"
Stoping Selenium
![](http://tin.javaeye.com/Images/dot.gif)
"
);
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估计要撇嘴
了
![](http://tin.javaeye.com/Emoticons/74_74.gif)
2、JVM级别钩子法
因为JVM支持关闭时执行制定代码的钩子,而static代码会在类初始化时执行,再加上Ant调用的是类似命令行的java命令,实际上每一个测试运行在一个完整的JVM启动关闭周期里面,所以也就产生了这种解决方案。
这个方案来自taowen同学的两则Selenium经验
。
代码我恢复了一下,大概是这样:
public
abstract
class
SomeTestCase
extends
TestCase {
static
{
//
perform the "global" set up logic
//
这里的代码会在类初始化时执行,所以相当于BeforeClass
log.debug(
"
Starting Selenium
![](http://tin.javaeye.com/Images/dot.gif)
"
);
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
![](http://tin.javaeye.com/Images/dot.gif)
"
);
selenium.stop();
}
}
);
}
}
这个方法挺酷的,我认为完全可以被称作“奇技淫巧”。缺点就是,有点不好看。
3、还有别的方法,这个来自Selenium网站,似乎是不错的中庸方案。
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
相关文章推荐
- 在JUnit中多个testCase只执行一次setup和tearDown的方法
- 让一个继承unittest.TestCase的类下的setUp和tearDown只执行一次
- JUnit测试中setup()和teardown()方法
- Junit测试中的setup和teardown 和 @before 和 @After 方法
- JUnit单元测试中的setUpBeforeClass()、tearDownAfterClass()、setUp()、tearDown()方法小结
- JUnit测试中setup()和teardown()方法
- jquery 全选和取消只能执行一次解决方法
- C#(.net)中的一次连接数据库执行多条sql语句(两种方法)
- JS设置页面中方法执行一次的思想
- Junit 第一讲:Junit中方法的执行顺序
- 异或加密法 在对文本进行简单加密的时候,可以选择用一个n位的二进制数,对原文进行异或运算。 解密的方法就是再执行一次同样的操作。
- iOS 单例模式 学习 "52个方法 第6章 45条 使用 dispath_once 来执行只需运行一次的线程安全代码"
- 每隔一段时间自动执行一次某个方法(使用线程)[C#]
- 防止window.showModalDialog 打开的页面 Page_Load 只执行一次的方法
- Struts2 请求一次Action,却执行两次方法的解决
- crontab每10秒执行一次的实现方法
- js每隔5分钟执行一次ajax请求的实现方法
- C#一次连接数据库执行多条sql语句(三种方法)
- Ajax在IE上做轮询时setInterval方法只执行一次
- 执行顺序:(优先级从高到低)静态代码块>mian方法>构造代码块>构造方法。 其中静态代码块只执行一次。构造代码块在每次创建对象是都会执行。