Java 当中间件失败时,有没有办法让集成测试快速失败?
我们的测试环境有多种依赖中间件的集成测试(CMS平台、底层数据库、Elasticsearch索引) 它们是自动化的,我们使用Docker管理我们的中间件,所以我们不会遇到不可靠网络的问题。然而,有时我们的数据库崩溃,测试失败 问题在于,对该故障的检测是通过一连串的Java 当中间件失败时,有没有办法让集成测试快速失败?,java,maven,integration-testing,Java,Maven,Integration Testing,我们的测试环境有多种依赖中间件的集成测试(CMS平台、底层数据库、Elasticsearch索引) 它们是自动化的,我们使用Docker管理我们的中间件,所以我们不会遇到不可靠网络的问题。然而,有时我们的数据库崩溃,测试失败 问题在于,对该故障的检测是通过一连串的org.hibernate.exception.JDBCConnectionException消息进行的。这些都是通过超时来实现的。当这种情况发生时,我们最终会有数百个测试因此异常而失败,每一个测试都要花几秒钟才能失败。因此,我们的测试
org.hibernate.exception.JDBCConnectionException
消息进行的。这些都是通过超时来实现的。当这种情况发生时,我们最终会有数百个测试因此异常而失败,每一个测试都要花几秒钟才能失败。因此,我们的测试需要一段时间才能完成。事实上,当我们意识到这些构建已经完成时,我们通常只是手动终止它们
我的问题:在Maven驱动的Java测试环境中,是否有一种方法可以指导构建系统注意特定类型的异常并终止整个过程,如果它们到达(或达到某种阈值)
我们可以监视我们的容器并以这种方式终止构建过程,但我希望有一种更干净的方法来使用maven。我不知道构建本身是否可以快速失败,或者甚至想要失败-因为构建的管理方面可能无法完成,但您可以这样做: 在所有依赖于数据库的测试类中,或者在父类中,因为类似这样的内容是可继承的,添加以下内容:
@BeforeClass
public void testJdbc() throws Exception {
Executors.newSingleThreadExecutor()
.submit(new Callable() {
public Object call() throws Exception {
// execute the simplest SQL you can, eg. "SELECT 1"
return null;
}
})
.get(100, TimeUnit.MILLISECONDS);
}
如果JDBC简单查询未能在100ms内返回,则整个测试类将不会运行,并将在构建中显示为“失败”
尽可能缩短等待时间并保持可靠。我意识到这并不是您所要求的,但仍然可以帮助加快构建速度: 允许在假设失败时让测试通过。您可以假设(db.isReachable())在达到超时时跳过这些测试 为了实际加快速度并避免重复,您可以将其放入
@ClassRule
:
@Before或@BeforeClass方法中的失败假设与该类的每个@Test方法中的失败假设具有相同的效果
当然,您必须通过另一种方式将构建标记为不稳定,但这应该是很容易做到的。如果您使用TestNG而不是JUnit,那么还可以将测试定义为依赖于其他测试 例如,像上面提到的其他方法一样,您可以有一个方法来检查数据库连接并声明所有其他测试依赖于此方法
@Test
public void serverIsReachable() {}
@Test(dependsOnMethods = { "serverIsReachable" })
public void queryTestOne() {}
这样,如果serverIsReachable
测试失败,则将跳过依赖于此测试的所有其他测试,并且不会标记为失败。跳过的方法将在最终报告中报告,这一点很重要,因为跳过的方法不一定是失败的但是由于您的初始测试serverIsReachable
失败,因此构建应该完全失败。
积极的影响是,将执行其他测试中的非测试,这应该会很快失败
您还可以使用组扩展此逻辑。假设您的数据库查询被一些域逻辑测试使用,您可以用一个组声明每个数据库测试,如
@Test(groups = { "jdbc" })
public void queryTestOne() {}
并声明域逻辑测试依赖于这些测试
@Test(dependsOnGroups = { "jdbc.* })
public void domainTestOne() {}
因此,TestNG将保证测试的执行顺序
希望这有助于使您的测试更有条理。有关更多信息,请查看。您可以做的一件事是编写一个新的测试运行程序,如果出现这种错误,它将停止运行。下面是一个可能的示例:
import org.junit.internal.AssumptionViolatedException;
import org.junit.runner.Description;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.Statement;
public class StopAfterSpecialExceptionRunner extends BlockJUnit4ClassRunner {
private boolean failedWithSpecialException = false;
public StopAfterSpecialExceptionRunner(Class<?> klass) throws InitializationError {
super(klass);
}
@Override
protected void runChild(final FrameworkMethod method, RunNotifier notifier) {
Description description = describeChild(method);
if (failedWithSpecialException || isIgnored(method)) {
notifier.fireTestIgnored(description);
} else {
runLeaf(methodBlock(method), description, notifier);
}
}
@Override
protected Statement methodBlock(FrameworkMethod method) {
return new FeedbackIfSpecialExceptionOccurs(super.methodBlock(method));
}
private class FeedbackIfSpecialExceptionOccurs extends Statement {
private final Statement next;
public FeedbackIfSpecialExceptionOccurs(Statement next) {
super();
this.next = next;
}
@Override
public void evaluate() throws Throwable {
boolean complete = false;
try {
next.evaluate();
complete = true;
} catch (AssumptionViolatedException e) {
throw e;
} catch (SpecialException e) {
StopAfterSpecialExceptionRunner.this.failedWithSpecialException = true;
throw e;
}
}
}
}
import org.junit.internal.AssumptionViolatedException;
导入org.junit.runner.Description;
导入org.junit.runner.notification.RunNotifier;
导入org.junit.runners.BlockJUnit4ClassRunner;
导入org.junit.runners.model.FrameworkMethod;
导入org.junit.runners.model.InitializationError;
导入org.junit.runners.model.Statement;
公共类StopAfterSpecialExceptionRunner扩展了BlockJUnit4ClassRunner{
private boolean Failed with SpecialException=false;
public StopAfterSpecialExceptionRunner(类klass)引发初始化错误{
超级(klass);;
}
@凌驾
受保护的void runChild(最终框架方法,RunNotifier通知程序){
描述=描述儿童(方法);
如果(因特殊异常而失败| |识别(方法)){
通知程序。fireTestIgnored(说明);
}否则{
runLeaf(methodBlock(方法)、描述、通知程序);
}
}
@凌驾
受保护语句methodBlock(FrameworkMethod方法){
返回新的反馈IfSpecialExceptionOccurs(super.methodBlock(method));
}
私有类反馈IfSpecialExceptionOccurs扩展语句{
下一步是非公开最终声明;
公共反馈IfSpecialExceptionOccurs(下一个声明){
超级();
this.next=next;
}
@凌驾
public void evaluate()可丢弃{
布尔完成=假;
试一试{
接下来,evaluate();
完整=正确;
}捕获(假设违反异常e){
投掷e;
}捕获(特例e){
StopAfterSpecialExceptionRunner.this.Failed,SpecialException=true;
投掷e;
}
}
}
}
然后用@RunWith(StopAfterSpecialExceptionRunner.class)
注释测试类
基本上,这是检查某个异常(这里是SpecialException
,一个我自己编写的异常),如果发生这种情况,它将使抛出该异常的测试失败,并跳过所有后续测试。你当然可以把它限制在