Я работаю с 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работает так, как ожидается.
Я создал пользовательские 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 {
...
}
Таким образом, если я попытаюсь использовать:
@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 переопределен.
по CompleteRule никогда не выполняется.
Я пробовал использовать
@Rule
public TestRule chain = RuleChain.outerRule(SPRING_CLASS_RULE)
.around(completeRule);
И не работает. Невозможно даже худшего добавить SpringMethodRule, потому что он реализует MethodRule, а не TestRule, как того требует метод around.
Я хочу избежать использования hierarchy и вместо этого работать с Rules. Это потому, что это лучшая практика.
Таким образом: есть ли способ обойти это?
Примечание Я нашел в другом посте, как предложение создать @Rule и вложить другие правила. К сожалению, нет примеров этого подхода, чтобы проверить его.
Примечание очень важен для работы с @RunWith(Parameterized.class), потому что обязательно использовать @Parameters(name = "{index}: ''{0}''").
SpringClassRule и SpringMethodRule предназначены для этого в соответствии с их API.




Сценарий, который вы описываете, фактически описан в SPR-15927.
Невозможно, чтобы пользовательский TestRule, внедренный Spring, фактически принимался JUnit как правило, если Spring также настроен с помощью правил (например, через SpringClassRule и SpringMethodRule).
Пользовательское поле TestRule на самом деле будет введено Spring, но это уже слишком поздно.
Другими словами, к тому времени, когда правила Spring будут использоваться для выполнения внедрения зависимостей, текущий Runner не заметит, что введенный пользовательский TestRule существует, поскольку поле ранее было null во время фазы обнаружения правила.
По сути, это проблема «курицы и яйца», и для JUnit 4 нет встроенного обходного пути.
Однако вы можете добиться чего-то подобного с помощью спрашивая Spring для выполнения внедрения зависимостей в существующее правило, но для этого требуется специальный код. Подробнее см. SPR-10252.
С JUnit Jupiter 5.1 это должно быть легче сделать. А именно, вы можете без проблем объединить поддержку параметризованного тестирования со Spring.
Уловка с JUnit Jupiter заключается в том, чтобы убедиться, что вы зарегистрировали SpringExtension на уровне класса (например, через @ExtendWith, @SpringJUnitConfig или аналогичный). Затем вы можете использовать @RegisterExtension и @Autowired в поле, чтобы добавить управляемое Spring расширение в тестовый экземпляр а также, используемый JUnit Jupiter.
Спасибо за ценное объяснение, поэтому я собираюсь перейти к
JUnit5. Вы помните, когда я создавал проблему с JUnit 5 в Github? Я поделился там некоторым кодом о моих собственных экспериментах по миграции, и для"Parameterized"больше не было необходимости использоватьSpringClassRuleиSpringMethodRule. Теперь, если моя память меня не подводит, TestRule больше не существует в JUnit 5.