如何使用自定义@Rule正确配置@RunWith(Parameterized.class)+ SpringClassRule + SpringMethodRule?

Man*_*dan 2 java junit spring spring-test junit5

我正在使用Spring Framework4.3.x和JUnit4,我有以下结构

@Transactional
@WebAppConfiguration
@RunWith(Parameterized.class)
@ContextConfiguration(classes={RootApplicationContext.class, ServletApplicationContext.class})
@TestExecutionListeners(listeners={LoggingTestExecutionListener.class}, mergeMode=MergeMode.MERGE_WITH_DEFAULTS)
public class CompleteTest {

    @ClassRule
    public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();

    @Rule
    public final SpringMethodRule springMethodRule = new SpringMethodRule();
Run Code Online (Sandbox Code Playgroud)

因此组合:

  • @RunWith(Parameterized.class)+ SpringClassRule+SpringMethodRule

工作如何预期.

TestRule通过ExternalResource以下方式创建了一个自定义:

@Component
public class CompleteRule extends ExternalResource {

    private static final Logger logger = LoggerFactory.getLogger(CompleteRule.class.getSimpleName());

    private final WebApplicationContext webApplicationContext;

    private final Environment environment;

    private MockMvc mockMvc;

    public CompleteRule(WebApplicationContext webApplicationContext, Environment environment) {
        this.webApplicationContext = webApplicationContext;
        this.environment = environment;
    }

    @Override
    protected void before() throws Throwable {
      ...
    }
Run Code Online (Sandbox Code Playgroud)

因此如果我尝试然后使用:

@Transactional
@WebAppConfiguration
@RunWith(Parameterized.class)
@ContextConfiguration(classes={RootApplicationContext.class, ServletApplicationContext.class})
@TestExecutionListeners(listeners={LoggingTestExecutionListener.class}, mergeMode=MergeMode.MERGE_WITH_DEFAULTS)
public class CompleteTest {

    private static final Logger logger = LoggerFactory.getLogger(CompleteTest.class.getSimpleName());

    @Rule
    @Autowired
    public CompleteRule completeRule;

    @ClassRule
    public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();

    @Rule
    public final SpringMethodRule springMethodRule = new SpringMethodRule();
Run Code Online (Sandbox Code Playgroud)

CompleteRule总是被忽略,这意味着ExternalResource.before通过覆盖方法CompleteRule永远不会执行.

我试过用

@Rule
public TestRule chain = RuleChain.outerRule(SPRING_CLASS_RULE)
                                                .around(completeRule);
Run Code Online (Sandbox Code Playgroud)

并不起作用.即使是最糟糕的是不可能的添加SpringMethodRule,因为它实现MethodRule,而不是TestRule该怎么around方法询问.

我希望避免使用hierarchyRules改为使用.这是因为这是一种最佳实践.

因此:有没有办法解决这个问题?

注意我在其他帖子中发现了一个建议如何创建@Rule和嵌套其他规则.遗憾的是没有关于这种测试方法的样本.

注意是非常重要的工作,@RunWith(Parameterized.class)因为是强制使用@Parameters(name="{index}: ''{0}''") ,SpringClassRule并且SpringMethodRule是根据其API设计的.

Sam*_*nen 6

JUnit 4

您描述的场景实际上涵盖在SPR-15927中.

这是不可能有一个自定义TestRule的春天注入居然拿起一个规则由JUnit的春天是否也通过规则配置(例如,通过SpringClassRuleSpringMethodRule).

TestRule事实上,自定义字段将由Spring注入,但这在游戏中已经太晚了.

换句话说,当Spring规则用于执行依赖注入时,当前Runner将不会注意到注入的自定义TestRule存在,因为该字段先前null在规则检测阶段期间.

它基本上是一个"鸡和蛋"的问题,而且JUnit 4没有内置的解决方法.

但是,您可以通过要求 Spring对现有规则执行依赖项注入来实现类似的操作,但这需要自定义代码.有关详细信息,请参见SPR-10252.

JUnit Jupiter(JUnit 5)

使用JUnit Jupiter 5.1,这实际上应该更容易实现.也就是说,您可以将参数化测试支持与Spring相结合而不会出现任何问题.

使用JUnit木星关键是要确保你注册SpringExtension在类级别(例如,通过@ExtendWith,@SpringJUnitConfig或类似).然后你就可以使用@RegisterExtension,并@Autowired在现场有一个Spring管理扩展注入测试实例,并使用JUnit的木星.