关键词:
【中文标题】在 JUnit 5 中,如何在所有测试之前运行代码【英文标题】:In JUnit 5, how to run code before all tests 【发布时间】:2017-09-03 02:44:38 【问题描述】:@BeforeAll
注释标记了一个方法,该方法要在一个类中的所有测试之前运行。
http://junit.org/junit5/docs/current/user-guide/#writing-tests-annotations
但是有没有办法在所有类的all 测试之前运行一些代码?
我想确保测试使用一组特定的数据库连接,并且这些连接的全局一次性设置必须发生在运行任何测试之前。 p>
【问题讨论】:
仅作记录:如果您发现其中一个答案足够有用 - 请考虑在某个时候接受其中一个 ;-) 【参考方案1】:现在可以通过创建自定义扩展在 JUnit5 中实现,您可以在根测试上下文中注册关闭挂钩。
您的扩展程序将如下所示;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import static org.junit.jupiter.api.extension.ExtensionContext.Namespace.GLOBAL;
public class YourExtension implements BeforeAllCallback, ExtensionContext.Store.CloseableResource
private static boolean started = false;
@Override
public void beforeAll(ExtensionContext context)
if (!started)
started = true;
// Your "before all tests" startup logic goes here
// The following line registers a callback hook when the root test context is shut down
context.getRoot().getStore(GLOBAL).put("any unique name", this);
@Override
public void close()
// Your "after all tests" logic goes here
然后,您需要至少执行一次的任何测试类都可以使用以下注释:
@ExtendWith(YourExtension.class)
当你在多个类上使用这个扩展时,启动和关闭逻辑只会被调用一次。
【讨论】:
如果您需要为每个测试类执行此操作,那么您还可以使用 automatic extension regristration 使用 ServiceLoader 注册扩展。然后你就不需要注释每一个测试(你可能会错过一些风险)。 在我的情况下,来自CloseableResource
的close
未被调用,但来自AfterAllCallback
的afterAll
被调用
FWIW 我用 Spring 实现了这个以使用 DataSource bean 设置测试数据,它工作得很好; ***.com/a/62504238/278800 中的详细信息。没有您的帮助,我无法做到这一点,谢谢!
我忍不住,不得不发布一个华丽的“走得更远”的答案。如果您认为它增加了 convo,请投票:***.com/a/65450782/5957643
我extended提供的样本在并行执行以及上面提到的自动扩展注册中都是有效的。【参考方案2】:
@Philipp Gayret 已经提供的答案在并行(即junit.jupiter.execution.parallel.enabled = true
)中测试JUnit 时存在一些问题。
因此我将解决方案调整为:
import static org.junit.jupiter.api.extension.ExtensionContext.Namespace.GLOBAL;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
public class BeforeAllTestsExtension extends BasicTestClass
implements BeforeAllCallback, ExtensionContext.Store.CloseableResource
private static boolean started = false;
// Gate keeper to prevent multiple Threads within the same routine
final static Lock lock = new ReentrantLock();
@Override
public void beforeAll(final ExtensionContext context) throws Exception
// lock the access so only one Thread has access to it
lock.lock();
if (!started)
started = true;
// Your "before all tests" startup logic goes here
// The following line registers a callback hook when the root test context is
// shut down
context.getRoot().getStore(GLOBAL).put("any unique name", this);
// do your work - which might take some time -
// or just uses more time than the simple check of a boolean
// free the access
lock.unlock();
@Override
public void close()
// Your "after all tests" logic goes here
如下所述,JUnit5 提供了一个自动的Extension Registration。为此,在src/test/resources/
中添加一个名为/META-INF/services
的目录并添加一个名为org.junit.jupiter.api.extension.Extension
的文件。在此文件中添加您的班级的完全分类名称,例如
at.myPackage.BeforeAllTestsExtension
接下来在同一个 Junit 配置文件中启用
junit.jupiter.extensions.autodetection.enabled=true
这样,扩展程序会自动附加到您的所有测试中。
【讨论】:
完美运行!提示:扩展类必须是公共的,就像这个例子中一样【参考方案3】:根据@Philipp 的建议,这里有一个更完整的代码 sn-p:
import static org.junit.jupiter.api.extension.ExtensionContext.Namespace.GLOBAL;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
public abstract class BaseSetupExtension
implements BeforeAllCallback, ExtensionContext.Store.CloseableResource
@Override
public void beforeAll(ExtensionContext context) throws Exception
// We need to use a unique key here, across all usages of this particular extension.
String uniqueKey = this.getClass().getName();
Object value = context.getRoot().getStore(GLOBAL).get(uniqueKey);
if (value == null)
// First test container invocation.
context.getRoot().getStore(GLOBAL).put(uniqueKey, this);
setup();
// Callback that is invoked <em>exactly once</em>
// before the start of <em>all</em> test containers.
abstract void setup();
// Callback that is invoked <em>exactly once</em>
// after the end of <em>all</em> test containers.
// Inherited from @code CloseableResource
public abstract void close() throws Throwable;
使用方法:
public class DemoSetupExtension extends BaseSetupExtension
@Override
void setup()
@Override
public void close() throws Throwable
@ExtendWith(DemoSetupExtension.class)
public class TestOne
@BeforeAll
public void beforeAllTestOne ...
@Test
public void testOne ...
@ExtendWith(DemoSetupExtension.class)
public class TestTwo
@BeforeAll
public void beforeAllTestTwo ...
@Test
public void testTwo ...
测试执行顺序为:
DemoSetupExtension.setup (*)
TestOne.beforeAllTestOne
TestOne.testOne
TestOne.afterAllTestOne
TestTwo.beforeAllTestTwo
TestTwo.testTwo
TestTwo.afterAllTestTwo
DemoSetupExtension.close (*)
...无论您是否选择运行单个 @Test(例如 TestOne.testOne),或整个测试类 (TestOne),或多个/所有测试。
【讨论】:
第一次工作,结合auto-registering extensions上的信息。 它如何/为什么只关闭一次?大概:junit.org/junit5/docs/current/user-guide/…【参考方案4】:您可以使用定义static
BeforeAll
的接口标记每个使用数据库的测试类(这样它就不能被覆盖)。例如:
interface UsesDatabase
@BeforeAll
static void initializeDatabaseConnections()
// initialize database connections
每个实现类都会调用一次此方法,因此您需要定义一种方法来只初始化一次连接,然后对其他调用不执行任何操作。
【讨论】:
【参考方案5】:我不知道这样做的意思。
我会简单地确保 @BeforeAll 的所有代码调用某个单例以使该 init 工作(可能以一种懒惰的方式避免重复)。
可能不方便......我看到的唯一其他选择:我假设您的测试在特定的 JVM 作业中运行。您可以将 agent 挂接到该 JVM 运行中,该初始化为您工作。
除此之外:这两个建议对我来说听起来都像是一种黑客行为。在我看来,真正的答案是:退后一步,仔细检查你的环境的依赖关系。然后找到一种方法来准备您的环境,使您的测试出现并且“正确的事情”自动发生。换句话说:考虑调查给你带来这个问题的架构。
【讨论】:
【参考方案6】:以上建议不对我有用,所以我这样解决了这个问题:
将这部分代码添加到您的 Base 抽象类(我的意思是您在 setUpDriver() 方法中初始化驱动程序的抽象类):
private static boolean started = false;
static
if (!started)
started = true;
try
setUpDriver(); //method where you initialize your driver
catch (MalformedURLException e)
现在,如果您的测试类将从基础抽象类扩展 -> setUpDriver() 方法将在第一个 @Test 之前执行 ONE 每个项目运行的时间。
【讨论】:
【参考方案7】:这是我对 @Phillip Gayret 非常好的答案的 POC 改进,紧随 @Mihnea Giurgea 的脚步。
我的子问题:如何访问共享单例资源?(也许你也想知道这个......)
侧边栏: 在我的实验过程中,我发现使用多个 @ExtendWith(...)
似乎可以正确嵌套。即便如此,我记得在我摸索的时候它并没有那样工作,所以你应该确保你的用例正常工作[原文如此]。
因为你可能很着急,甜点是第一位的:这是运行“文件夹内的所有测试”的输出:
NestedSingleton::beforeAll (setting resource)
Singleton::Start-Once
Base::beforeAll
Colors::blue - resource=Something nice to share!
Colors::gold - resource=Something nice to share!
Base::afterAll
Base::beforeAll
Numbers::one - resource=Something nice to share!
Numbers::tre - resource=Something nice to share!
Numbers::two - resource=Something nice to share!
Base::afterAll
Singleton::Finish-Once
NestedSingleton::close (clearing resource)
当然,只运行一个测试类就可以:
NestedSingleton::beforeAll (setting resource)
Singleton::Start-Once
Base::beforeAll
Numbers::one - resource=Something nice to share!
Numbers::tre - resource=Something nice to share!
Numbers::two - resource=Something nice to share!
Base::afterAll
Singleton::Finish-Once
NestedSingleton::close (clearing resource)
还有一个具体的测试,正如现在可以预料的那样:
NestedSingleton::beforeAll (setting resource)
Singleton::Start-Once
Base::beforeAll
Colors::gold - resource=Something nice to share!
Base::afterAll
Singleton::Finish-Once
NestedSingleton::close (clearing resource)
还和我在一起吗?那么你可能会喜欢看到实际的代码......
======================================================
junitsingletonresource/Base.java
======================================================
package junitsingletonresource;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.extension.ExtendWith;
@ExtendWith(Singleton.class)
public abstract class Base extends BaseNestedSingleton
@BeforeAll public static void beforeAll() System.out.println("Base::beforeAll");
@AfterAll public static void afterAll () System.out.println("Base::afterAll" );
======================================================
junitsingletonresource/Colors.java
======================================================
package junitsingletonresource;
import org.junit.jupiter.api.Test;
public class Colors extends Base
@Test public void blue() System.out.println("Colors::blue - resource=" + getResource());
@Test public void gold() System.out.println("Colors::gold - resource=" + getResource());
======================================================
junitsingletonresource/Numbers.java
======================================================
package junitsingletonresource;
import org.junit.jupiter.api.Test;
public class Numbers extends Base
@Test public void one() System.out.println("Numbers::one - resource=" + getResource());
@Test public void two() System.out.println("Numbers::two - resource=" + getResource());
@Test public void tre() System.out.println("Numbers::tre - resource=" + getResource());
======================================================
junitsingletonresource/BaseNestedSingleton.java
======================================================
package junitsingletonresource;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.ExtensionContext;
import static org.junit.jupiter.api.extension.ExtensionContext.Namespace.GLOBAL;
/**
* My riff on Phillip Gayret's solution from: https://***.com/a/51556718/5957643
*/
@ExtendWith(BaseNestedSingleton.NestedSingleton.class)
public abstract class BaseNestedSingleton
protected String getResource() return NestedSingleton.getResource();
static /*pkg*/ class NestedSingleton implements BeforeAllCallback, ExtensionContext.Store.CloseableResource
private static boolean initialized = false;
private static String resource = "Tests should never see this value (e.g. could be null)";
private static String getResource() return resource;
@Override
public void beforeAll(ExtensionContext context)
if (!initialized)
initialized = true;
// The following line registers a callback hook when the root test context is shut down
context.getRoot().getStore(GLOBAL).put(this.getClass().getCanonicalName(), this);
// Your "before all tests" startup logic goes here, e.g. making connections,
// loading in-memory DB, waiting for external resources to "warm up", etc.
System.out.println("NestedSingleton::beforeAll (setting resource)");
resource = "Something nice to share!";
@Override
public void close()
if (!initialized) throw new RuntimeException("Oops - this should never happen");
// Cleanup the resource if needed, e.g. flush files, gracefully end connections, bury any corpses, etc.
System.out.println("NestedSingleton::close (clearing resource)");
resource = null;
======================================================
junitsingletonresource/Singleton.java
======================================================
package junitsingletonresource;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import static org.junit.jupiter.api.extension.ExtensionContext.Namespace.GLOBAL;
/**
* This is pretty much what Phillip Gayret provided, but with some printing for traceability
*/
public class Singleton implements BeforeAllCallback, ExtensionContext.Store.CloseableResource
private static boolean started = false;
@Override
public void beforeAll(ExtensionContext context)
if (!started)
started = true;
System.out.println("Singleton::Start-Once");
context.getRoot().getStore(GLOBAL).put("any unique name", this);
@Override
public void close() System.out.println("Singleton::Finish-Once");
【讨论】:
如何在测试失败后但在任何 @After 方法之前让 JUnit 4.8 运行代码?
】如何在测试失败后但在任何@After方法之前让JUnit4.8运行代码?【英文标题】:HowcanImakeJUnit4.8runcodeafterafailedtest,butbeforeany@Aftermethods?【发布时间】:2012-01-2318:01:25【问题描述】:我正在使用JUnit4.8.2进行一套Selenium测试(实际上是W... 查看详情
java示例代码_使用Ant在一个类别/套件中运行所有JUnit测试
java示例代码_使用Ant在一个类别/套件中运行所有JUnit测试 查看详情
JUnit 如何管理在测试类中定义的仅运行一次 @BeforeClass
】JUnit如何管理在测试类中定义的仅运行一次@BeforeClass【英文标题】:HowJUnitmanagesrunning@BeforeClassonlyoncewhichisdefinedinsidethetestclass【发布时间】:2013-12-0307:37:00【问题描述】:我非常了解@BeforeClass是什么。它在JUnit测试运行开始之前... 查看详情
java示例代码_在JUnit中,如何获得所有集成测试的列表
java示例代码_在JUnit中,如何获得所有集成测试的列表 查看详情
在 Junit 4 中运行所有测试
】在Junit4中运行所有测试【英文标题】:RunalltestsinJunit4【发布时间】:2010-02-1220:53:02【问题描述】:我希望能够以编程方式运行项目中的所有测试。我知道Eclipse有一个“作为JUnit测试运行”配置,它以某种方式获取项目中的所... 查看详情
在 Junit 5 中,如何从扩展中调用测试类方法?
】在Junit5中,如何从扩展中调用测试类方法?【英文标题】:InJunit5howcanIcallatestclassmethodfromanextension?【发布时间】:2021-02-0721:25:15【问题描述】:在Junit5中,我试图让测试类方法从扩展中运行。我正在使用Junit5扩展接口TestWatcher... 查看详情
使用 Test::Unit,如何在所有测试(但不是每个测试)之前运行一些代码?
】使用Test::Unit,如何在所有测试(但不是每个测试)之前运行一些代码?【英文标题】:WithTest::Unit,howcanIrunabitofcodebeforealltests(butnoteachtest)?【发布时间】:2011-10-1116:36:31【问题描述】:在我使用test::unit的测试应用程序中,我需... 查看详情
深入探索junit4(代码片段)
...异常测试、参数测试以及新的灵活固件模型。您还将了解如何声明测试,如何使用注释(而不是套件)在运行测试前从逻辑上对其分组,如何在Eclipse3.2或Ant中运行测试,以及如何从命令行运行测试。先决条件为更好地学习本教... 查看详情
java示例代码_在使用ANT运行类或套件中的所有测试时,打印当前正在执行的junit测试方法
java示例代码_在使用ANT运行类或套件中的所有测试时,打印当前正在执行的junit测试方法 查看详情
如何在没有 Maven 的情况下同时运行 Eclipse Java 项目的所有 JUnit 测试?
】如何在没有Maven的情况下同时运行EclipseJava项目的所有JUnit测试?【英文标题】:HowtosimultaneouslyrunallJUnittestsforaEclipseJavaprojectwithoutMaven?【发布时间】:2011-08-1104:52:58【问题描述】:我在Eclipse中有一个小型Java项目。我对项目中的... 查看详情
Maven 和 JUnit 5:在一个类中运行单个测试
】Maven和JUnit5:在一个类中运行单个测试【英文标题】:MavenandJUnit5:runasingletestinaclass【发布时间】:2018-02-0518:37:47【问题描述】:我一直在尝试使用Maven(版本3.3.9)和JUnit5(非4)在一个类中使用以下命令运行单个测试,但未成... 查看详情
在 Gradle 中,如何在每次执行 JUnit 测试类之前设置唯一的系统属性?
】在Gradle中,如何在每次执行JUnit测试类之前设置唯一的系统属性?【英文标题】:InGradle,howtosetuniquesystempropertybeforeeachexecutionofJUnittestclass?【发布时间】:2017-12-0920:23:17【问题描述】:在下面的gradle脚本中,maxParallelForks和forkEver... 查看详情
如何使用 JVM 参数在终端中通过 maven 运行 junit 测试
】如何使用JVM参数在终端中通过maven运行junit测试【英文标题】:HowtorunjunittestsbymaveninterminalwithJVMarguments【发布时间】:2017-05-2505:23:39【问题描述】:正如here中提到的,我们可以使用以下方法运行测试方法,mvn-Dtest=TestCircle#xyztest... 查看详情
junit学习(代码片段)
...例之前)2021@BeforeClass+方法:22指示附着的静态方法,在所有的测试之前必须运行一次,发生这种情况时一般是测试计算共享配置方法如连接到数据库(注意:是整个类执行之后)2324@After+方法:25测试后执行的内容,比如重置某些... 查看详情
在 JUnit 5 完成所有类测试后,测试容器未从 docker 中删除
】在JUnit5完成所有类测试后,测试容器未从docker中删除【英文标题】:TestcontainersnotdeletedfromdockerafterJUnit5allclasstestscompleted【发布时间】:2021-10-2416:11:53【问题描述】:我正在使用测试容器对micronaut应用程序进行集成测试和端到... 查看详情
junit4
...试方法之前运行4.@After:每一个测试方法之运行5.@BeforeClass:所有测试开始之前运行6.@AfterClass:所有测试结束之后运行&nb 查看详情
如何在 Rust 中运行任何测试之前运行设置代码?
】如何在Rust中运行任何测试之前运行设置代码?【英文标题】:HowtorunsetupcodebeforeanytestsruninRust?【发布时间】:2019-09-1907:39:04【问题描述】:我有一个Rust应用程序(一个简单的解释器),需要在环境可用之前进行一些设置(初... 查看详情
在 JUnit 5 测试类之间共享数据库连接
...使用的application.properties文件来设置数据库连接。问题是如何在第一个JUnit测试运行时创建数据库连接并将其重用于所有类。最后正确关闭连接。【问 查看详情