我们正在使用类似于System Rules的方法来处理JUnit 4测试中的(系统)属性。这样做的主要原因是每次测试后都要清理环境,这样其他测试就不会无意中依赖于可能的副作用。
自JUnit 5发布以来,我想知道是否有“JUnit 5方式”这样做?
答案 0 :(得分:6)
您可以使用extension 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"));
}
答案 1 :(得分:6)
有JUnit Pioneer,一个“ JUnit 5扩展包”。它带有@ClearSystemProperty
和@SetSystemProperty
。来自docs:
@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"));
}
答案 2 :(得分:0)
JUnit Pioneer方式要求在编译时知道系统属性。在运行时生成它们的地方,例如通过Testcontainers
或Wiremock
在随机端口上创建事物,最好使用可以由动态值驱动的事物。
可以使用提供JUnit 5的系统存根https://github.com/webcompere/system-stubs来解决该问题,该系统存根是系统Lambda的代码的分支,该代码本身由系统规则的作者构建。
@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
}
}