如何使用自定义@Rule 正确配置@RunWith(Parameterized.class) + SpringClassRule + SpringMethodRule?
How configure correctly @RunWith(Parameterized.class) + SpringClassRule + SpringMethodRule with a custom @Rule?
我正在使用 Spring Framework
4.3.x 和 JUnit
4,我有以下结构
@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();
因此组合:
@RunWith(Parameterized.class)
+ SpringClassRule
+ SpringMethodRule
按预期工作。
我通过 ExternalResource
创建了一个自定义 TestRule
如下:
@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 {
...
}
因此,如果我尝试使用:
@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();
CompleteRule
总是被忽略,这意味着ExternalResource.before
方法被覆盖了
by CompleteRule
永远不会被执行。
我试过使用
@Rule
public TestRule chain = RuleChain.outerRule(SPRING_CLASS_RULE)
.around(completeRule);
而且不起作用。更糟糕的是不可能添加 SpringMethodRule
因为它实现了 MethodRule
而不是 TestRule
如何实现 around
方法的要求。
我想避免使用 hierarchy
并改用 Rules
。这是因为这是最佳实践。
因此:是否有解决此问题的方法?
注意 我在其他 post 中找到了如何创建 @Rule
和嵌套其他规则的建议。遗憾的是没有关于这种方法的样本来测试它。
注意 是解决 @RunWith(Parameterized.class)
非常重要的工作,因为它是强制使用 @Parameters(name="{index}: ''{0}''")
SpringClassRule
和 SpringMethodRule
是根据他们的 API.
设计的
JUnit 4
您所描述的场景实际上包含在SPR-15927。
不可能让 Spring 注入的自定义 TestRule
实际上被 JUnit 拾取为 rule 如果 Spring 也是通过规则配置(例如,通过 SpringClassRule
和 SpringMethodRule
)。
自定义 TestRule
字段实际上将由 Spring 注入,但在游戏中为时已晚。
换句话说,当 Spring 规则被用来执行依赖注入时,当前 Runner
将不会注意到注入的自定义 TestRule
存在,因为字段之前在规则检测阶段null
。
这基本上是一个 "chicken and egg" 问题,JUnit 4 没有 built-in 解决方法。
但是,您可以通过 请求 Spring 对现有规则执行依赖项注入来实现类似的功能,但这需要自定义代码。有关详细信息,请参阅 SPR-10252。
JUnit 木星 (JUnit 5)
有了 JUnit Jupiter 5.1,这实际上应该更容易实现。也就是说,您可以毫无问题地将参数化测试支持与 Spring 结合使用。
JUnit Jupiter 的诀窍是确保您在 class 级别注册 SpringExtension
(例如,通过 @ExtendWith
、@SpringJUnitConfig
或类似方式)。然后,您可以在字段上使用 @RegisterExtension
和 @Autowired
将 Spring-managed 扩展注入到 JUnit Jupiter 使用的测试实例 和 中。
我正在使用 Spring Framework
4.3.x 和 JUnit
4,我有以下结构
@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();
因此组合:
@RunWith(Parameterized.class)
+SpringClassRule
+SpringMethodRule
按预期工作。
我通过 ExternalResource
创建了一个自定义 TestRule
如下:
@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 {
...
}
因此,如果我尝试使用:
@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();
CompleteRule
总是被忽略,这意味着ExternalResource.before
方法被覆盖了
by CompleteRule
永远不会被执行。
我试过使用
@Rule
public TestRule chain = RuleChain.outerRule(SPRING_CLASS_RULE)
.around(completeRule);
而且不起作用。更糟糕的是不可能添加 SpringMethodRule
因为它实现了 MethodRule
而不是 TestRule
如何实现 around
方法的要求。
我想避免使用 hierarchy
并改用 Rules
。这是因为这是最佳实践。
因此:是否有解决此问题的方法?
注意 我在其他 post 中找到了如何创建 @Rule
和嵌套其他规则的建议。遗憾的是没有关于这种方法的样本来测试它。
注意 是解决 @RunWith(Parameterized.class)
非常重要的工作,因为它是强制使用 @Parameters(name="{index}: ''{0}''")
SpringClassRule
和 SpringMethodRule
是根据他们的 API.
JUnit 4
您所描述的场景实际上包含在SPR-15927。
不可能让 Spring 注入的自定义 TestRule
实际上被 JUnit 拾取为 rule 如果 Spring 也是通过规则配置(例如,通过 SpringClassRule
和 SpringMethodRule
)。
自定义 TestRule
字段实际上将由 Spring 注入,但在游戏中为时已晚。
换句话说,当 Spring 规则被用来执行依赖注入时,当前 Runner
将不会注意到注入的自定义 TestRule
存在,因为字段之前在规则检测阶段null
。
这基本上是一个 "chicken and egg" 问题,JUnit 4 没有 built-in 解决方法。
但是,您可以通过 请求 Spring 对现有规则执行依赖项注入来实现类似的功能,但这需要自定义代码。有关详细信息,请参阅 SPR-10252。
JUnit 木星 (JUnit 5)
有了 JUnit Jupiter 5.1,这实际上应该更容易实现。也就是说,您可以毫无问题地将参数化测试支持与 Spring 结合使用。
JUnit Jupiter 的诀窍是确保您在 class 级别注册 SpringExtension
(例如,通过 @ExtendWith
、@SpringJUnitConfig
或类似方式)。然后,您可以在字段上使用 @RegisterExtension
和 @Autowired
将 Spring-managed 扩展注入到 JUnit Jupiter 使用的测试实例 和 中。