【问题标题】:Properly set (system) properties in JUnit 5在 JUnit 5 中正确设置(系统)属性
【发布时间】:2018-04-01 11:19:33
【问题描述】:

我们正在使用类似于System Rules 的方法来处理我们的 JUnit 4 测试中的(系统)属性。这样做的主要原因是在每次测试后清理环境,以便其他测试不会无意中依赖可能的副作用。

既然 JUnit 5 发布了,不知道有没有“JUnit 5 方式”来做这件事?

【问题讨论】:

  • JUnit5 现在一般来说对所有事情都有一个答案,它看起来像 - extension API。我自己没有玩过它,但我认为大多数东西都可以用它来表达。也就是说,JUnit4 方式对于你想要的仍然是完全可行的。
  • @M.Prokhorov 感谢您的提示,将看看扩展模型。

标签: java junit junit5


【解决方案1】:

您可以使用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"));
}

【讨论】:

  • 它是 JUnit5,所以它是 Java8,因此它具有可重复的注解,并且实际上不需要向用户公开 @SystemProperties 注解 - 只需将 @SystemProperty 标记为可重复并调用 getAnnotationS getAnnotation.
  • 无法通过从代码中点击 System.getenv() 来解决,
  • @ses 系统属性!= 环境变量。如果您必须处理后者,请查看此答案:stackoverflow.com/a/63494695/3429133
【解决方案2】:

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"));
}

【讨论】:

    【解决方案3】:

    JUnit Pioneer 方式要求在编译时知道系统属性。在运行时生成它们的地方,比如通过TestcontainersWiremock 在随机端口上创建东西,最好使用可以从动态值驱动的东西。

    这个问题可以通过 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
        }
    }
    
    

    【讨论】:

    • 可以使用 Pioneer 的 @ClearSystemProperty,然后将 System#setProperty(...) 用于非常量表达式,因此在编译时不需要知道值(参见 docs)。
    • 是的。因为System.setProperty 是一个非常容易使用的东西,它本身并不是什么大问题。然而,上面的好处是系统属性集可以在构造时在SystemProperties 对象中定义,或者在Before 方法中定义,并且在测试运行之前尚未应用于属性。更好的是 SystemStubs 的 EnvironmentVariables 替代方案,它对难以访问的环境变量执行相同的操作。
    猜你喜欢
    • 1970-01-01
    • 2017-04-17
    • 2016-07-02
    • 2017-09-24
    • 2012-06-15
    • 2011-11-03
    • 1970-01-01
    • 1970-01-01
    • 2014-02-04
    相关资源
    最近更新 更多