在 JUnit 5 中正确设置(系统)属性

问题描述 投票:0回答:3

我们使用类似于“系统规则”的方法来处理 JUnit 4 测试中的(系统)属性。这样做的主要原因是每次测试后都要清理环境,以免其他测试无意中依赖于可能的副作用。 自从 JUnit 5 发布以来,我想知道是否有“JUnit 5 方式”可以做到这一点?

java junit junit5
3个回答
28
投票
JUnit Pioneer

,一个“JUnit 5 扩展包”。它带有 @ClearSystemProperty

@SetSystemProperty
。来自
文档

@ClearSystemProperty

@SetSystemProperty
注释可分别用于清除和设置测试执行的系统属性值。这两个注释都适用于测试方法和类级别,是可重复的、可组合的,并且是从更高级别的容器继承的。被注解的方法执行后,注解中提到的属性将恢复为原来的值或上一层容器的值,如果之前没有,则被清除。测试期间更改的其他系统属性不会恢复 [...]

示例:

@Test @ClearSystemProperty(key = "some key") @SetSystemProperty(key = "another key", value = "new value") void test() { assertNull(System.getProperty("some key")); assertEquals("new value", System.getProperty("another key")); }

如果您在编译时不知道自己的值和/或想要参数化系统属性测试,则可以使用 
@RestoreSystemProperties

(自 v2.1.0 起)。来自

文档

@RestoreSystemProperties

可用于恢复直接在代码中对系统属性所做的更改。虽然

@ClearSystemProperty
@SetSystemProperty
设置或清除特定属性和值,但它们不允许计算或参数化属性值,因此有时您可能希望直接在测试代码中设置属性。
@RestoreSystemProperties
可以放置在测试方法或测试类上,并在测试或测试类完成后将所有系统属性完全恢复到原始状态。

示例:

@ParameterizedTest @ValueSource(strings = { "new value", "newer value" }) @RestoreSystemProperties void parameterizedTest(String value) { System.setProperty("some key", value); // ... }



13
投票
扩展API

。您可以创建一个注释来定义测试方法的扩展。 import org.junit.jupiter.api.extension.ExtendWith; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @ExtendWith(SystemPropertyExtension.class) public @interface SystemProperty { String key(); String value(); }

然后,您可以创建扩展类:

import org.junit.jupiter.api.extension.AfterEachCallback; import org.junit.jupiter.api.extension.BeforeEachCallback; import org.junit.jupiter.api.extension.ExtensionContext; public class SystemPropertyExtension implements AfterEachCallback, BeforeEachCallback { @Override public void afterEach(ExtensionContext extensionContext) throws Exception { SystemProperty annotation = extensionContext.getTestMethod().get().getAnnotation(SystemProperty.class); System.clearProperty(annotation.key()); } @Override public void beforeEach(ExtensionContext extensionContext) throws Exception { SystemProperty annotation = extensionContext.getTestMethod().get().getAnnotation(SystemProperty.class); System.setProperty(annotation.key(), annotation.value()); } }

最后,您可以使用属性注释您的测试:

@Test @SystemProperty(key = "key", value = "value") void testPropertey() { System.out.println(System.getProperty("key")); }

此解决方案仅支持每个测试的一个系统属性。如果你想支持多个测试,你可以使用嵌套注释,扩展也可以处理这个问题:

@Test @SystemProperties({ @SystemProperty(key = "key1", value = "value"), @SystemProperty(key = "key2", value = "value") }) void testPropertey() { System.out.println(System.getProperty("key1")); System.out.println(System.getProperty("key2")); }



4
投票
Testcontainers

Wiremock
在随机端口上创建东西,那么最好使用可以从动态值驱动的东西。
这个问题可以通过 System Stubs 来解决 

https://github.com/webcompere/system-stubs

它提供了 JUnit 5,是 System Lambda 代码的一个分支,它本身是由 System Rules 的作者构建的。 @ExtendWith(SystemStubsExtension.class) class SomeTest { // can be initialised here with some up front properties // or leave like this for auto initialization @SystemStub private SystemProperties someProperties; @BeforeEach void beforeEach() { someProperties.set("prop1", "value1") .set("prop2", "value2"); } @Test void someTest() { // properties are set here // and can also call System.setProperty // properties reset to state before the test case ran // as the test case is tidied up } }

© www.soinside.com 2019 - 2024. All rights reserved.