我们使用类似于“系统规则”的方法来处理 JUnit 4 测试中的(系统)属性。这样做的主要原因是每次测试后都要清理环境,以免其他测试无意中依赖于可能的副作用。 自从 JUnit 5 发布以来,我想知道是否有“JUnit 5 方式”可以做到这一点?
,一个“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);
// ...
}
。您可以创建一个注释来定义测试方法的扩展。
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"));
}
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
}
}