我想对(宁静的)网络服务进行一些功能测试。测试套件包含一堆测试用例,每个测试用例在 web 服务上执行几个 HTTP 请求。
自然,Web 服务必须运行,否则测试将失败。:-)
启动 web 服务需要几分钟(它会处理一些繁重的数据提升),所以我想尽可能不频繁地启动它(至少所有只有从服务中获取资源的测试用例才能共享一个)。
那么有没有办法在测试套件中设置炸弹,就像在测试用例的 @BeforeClass 方法中一样运行测试?
我想对(宁静的)网络服务进行一些功能测试。测试套件包含一堆测试用例,每个测试用例在 web 服务上执行几个 HTTP 请求。
自然,Web 服务必须运行,否则测试将失败。:-)
启动 web 服务需要几分钟(它会处理一些繁重的数据提升),所以我想尽可能不频繁地启动它(至少所有只有从服务中获取资源的测试用例才能共享一个)。
那么有没有办法在测试套件中设置炸弹,就像在测试用例的 @BeforeClass 方法中一样运行测试?
@ClassRule
现在的答案是在您的套件中创建一个。该规则将在每个测试类运行之前或之后(取决于您如何实现)被调用。您可以扩展/实现一些不同的基类。类规则的好处在于,如果您不将它们实现为匿名类,那么您可以重用代码!
这是一篇关于它们的文章:http: //java.dzone.com/articles/junit-49-class-and-suite-level-rules
下面是一些示例代码来说明它们的使用。是的,这是微不足道的,但它应该足以说明生命周期,以便您开始。
首先是套件定义:
import org.junit.*;
import org.junit.rules.ExternalResource;
import org.junit.runners.Suite;
import org.junit.runner.RunWith;
@RunWith( Suite.class )
@Suite.SuiteClasses( {
RuleTest.class,
} )
public class RuleSuite{
private static int bCount = 0;
private static int aCount = 0;
@ClassRule
public static ExternalResource testRule = new ExternalResource(){
@Override
protected void before() throws Throwable{
System.err.println( "before test class: " + ++bCount );
sss = "asdf";
};
@Override
protected void after(){
System.err.println( "after test class: " + ++aCount );
};
};
public static String sss;
}
现在测试类定义:
import static org.junit.Assert.*;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExternalResource;
public class RuleTest {
@Test
public void asdf1(){
assertNotNull( "A value should've been set by a rule.", RuleSuite.sss );
}
@Test
public void asdf2(){
assertEquals( "This value should be set by the rule.", "asdf", RuleSuite.sss );
}
}
jUnit 不能做那种事情——尽管 TestNG 确实有@BeforeSuite
和@AfterSuite
注释。通常,您需要构建系统来执行此操作。在 Maven 中,有“集成前测试”和“集成后测试”阶段。在 ANT 中,您只需将步骤添加到任务中。
您的问题几乎是jUnit 4.x 中的 Before and After Suite 执行挂钩,所以我会看看那里的建议。
一种选择是使用 Apache Ant 之类的东西来启动您的单元测试套件。然后,您可以在 junit 目标之前和之后进行目标调用,以启动和停止 Web 服务:
<target name="start.webservice"><!-- starts the webservice... --></target>
<target name="stop.webservice"><!-- stops the webservice... --></target>
<target name="unit.test"><!-- just runs the tests... --></target>
<target name="run.test.suite"
depends="start.webservice, unit.test, stop.webservice"/>
然后,您使用 ant(或您选择的集成工具)运行您的套件。大多数 IDE 都支持 Ant,这使得将测试转移到连续集成环境中变得更加容易(其中许多使用 Ant 目标来定义自己的测试)。
顺便说一句,让单元测试实际调用 Web 服务、数据库等外部资源是一个坏主意。
单元测试的运行速度应该非常快,并且每次运行套件都会延迟“几分钟”,这意味着它不会像应有的那样运行。
我的建议:
在单元测试中使用 EasyMock ( http://www.easymock.org/ ) 之类的东西来模拟外部依赖项。
使用 Fitnesse ( http://fitnesse.org/ ) 之类的东西或针对测试环境运行且持续运行的本土解决方案构建单独的集成测试套件。