问题描述
我正在使用 Spring Framework
4.3.x和 JUnit
4,我有以下结构
I am working with Spring Framework
4.3.x and JUnit
4, I have the following structure
@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
@RunWith(Parameterized.class)
+SpringClassRule
+SpringMethodRule
的工作方式如预期。
I已创建自定义 TestRule
到 ExternalResource
,如下所示:
I have created a custom TestRule
through ExternalResource
as follows:
@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
永远不会被执行。
The CompleteRule
is always ignored, it means the ExternalResource.before
method overriddenby CompleteRule
is never executed.
我尝试过使用
@Rule
public TestRule chain = RuleChain.outerRule(SPRING_CLASS_RULE)
.around(completeRule);
并且不起作用。甚至最糟糕的是无法添加 SpringMethodRule
因为它实现 MethodRule
而不是 TestRule
周围
方法的要求如何。
And does not work. Even worst is not possible add SpringMethodRule
because it implements MethodRule
and not TestRule
how the around
method asks for.
我想避免使用层次结构
并改为使用规则
。这是最好的做法。
I want avoid use hierarchy
and work around with Rules
instead. It because is a best practice.
因此:有没有办法解决这个问题?
Thus: Is there an approach to work around this?
注意我在其他帖子中发现了一个建议如何创建 @Rule
并嵌套其他规则。遗憾的是没有关于这种测试方法的样本。
Note I found in other post how a suggestion create @Rule
and nest other Rules. Sadly no samples about this approach to test it.
注意是非常重要的工作 @RunWith(Parameterized.class) )
因为必须使用 @Parameters(name ={index}:''{0}'')
和 SpringClassRule
和 SpringMethodRule
是根据他们的API设计的。
Note is very important work around @RunWith(Parameterized.class)
because is mandatory use @Parameters(name="{index}: ''{0}''")
and SpringClassRule
and SpringMethodRule
are designed for this according with their API.
- SpringClassRule
- SpringMethodRule
推荐答案
JUnit 4
您所描述的方案实际上涵盖在。
Spring注入的自定义 TestRule
实际上不可能作为规则通过JUnit,如果Spring也是通过规则配置的(例如,通过 SpringClassRule
和 SpringMethodRule
)。
It is impossible to have a custom TestRule
injected by Spring actually picked up as a rule by JUnit if Spring is also configured via rules (e.g., via SpringClassRule
and SpringMethodRule
).
自定义 TestRule
字段实际上是由Spring注入的,但这在游戏中已经太晚了。
The custom TestRule
field will in fact be injected by Spring, but that's too late in the game.
换句话说,当Spring规则用于执行依赖注入时,当前的 Runner
将不会注意到注入的自定义 TestRule
存在,因为在规则检测阶段该字段以前是 null
。
In other words, by the time the Spring rules are used to perform dependency injection, the current Runner
will not notice that the injected custom TestRule
exists, since the field was previously null
during the rule detection phase.
它基本上是一个鸡蛋和鸡蛋问题,并且JUnit 4没有内置的解决方法。
It's basically a "chicken and egg" problem, and there is no built-in workaround for JUnit 4.
但是,你可以通过要求 Spring对现有规则执行依赖注入,但这需要自定义代码。有关详细信息,请参见。
However, you can achieve something similar by asking Spring to perform dependency injection on an existing rule, but that requires custom code. See SPR-10252 for details.
使用JUnit Jupiter 5.1实际上这应该更容易实现。也就是说,您可以将参数化测试支持与Spring结合起来,没有任何问题。
With JUnit Jupiter 5.1 this should actually be easier to accomplish. Namely, you can combine parameterized test support with Spring without any problems.
使用JUnit Jupiter的技巧是确保注册 SpringExtension
在班级(例如,通过 @ExtendWith
, @SpringJUnitConfig
或类似)。然后,您可以在字段上使用 @RegisterExtension
和 @Autowired
,以便将Spring管理的扩展注入到测试实例中JUnit Jupiter使用和。
The trick with JUnit Jupiter is to make sure you register the SpringExtension
at the class level (e.g., via @ExtendWith
, @SpringJUnitConfig
, or similar). Then you can use @RegisterExtension
and @Autowired
on a field to have a Spring-managed extension injected into the test instance and used by JUnit Jupiter.
这篇关于如何使用自定义@Rule正确配置@RunWith(Parameterized.class)+ SpringClassRule + SpringMethodRule?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!