Как правильно настроить @RunWith (Parameterized.class) + SpringClassRule + SpringMethodRule с настраиваемым @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

работает так, как ожидается.

Я создал пользовательские 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.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
0
1 090
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

JUnit 4

Сценарий, который вы описываете, фактически описан в SPR-15927.

Невозможно, чтобы пользовательский TestRule, внедренный Spring, фактически принимался JUnit как правило, если Spring также настроен с помощью правил (например, через SpringClassRule и SpringMethodRule).

Пользовательское поле TestRule на самом деле будет введено Spring, но это уже слишком поздно.

Другими словами, к тому времени, когда правила Spring будут использоваться для выполнения внедрения зависимостей, текущий Runner не заметит, что введенный пользовательский TestRule существует, поскольку поле ранее было null во время фазы обнаружения правила.

По сути, это проблема «курицы и яйца», и для JUnit 4 нет встроенного обходного пути.

Однако вы можете добиться чего-то подобного с помощью спрашивая Spring для выполнения внедрения зависимостей в существующее правило, но для этого требуется специальный код. Подробнее см. SPR-10252.

JUnit Юпитер (JUnit 5)

С JUnit Jupiter 5.1 это должно быть легче сделать. А именно, вы можете без проблем объединить поддержку параметризованного тестирования со Spring.

Уловка с JUnit Jupiter заключается в том, чтобы убедиться, что вы зарегистрировали SpringExtension на уровне класса (например, через @ExtendWith, @SpringJUnitConfig или аналогичный). Затем вы можете использовать @RegisterExtension и @Autowired в поле, чтобы добавить управляемое Spring расширение в тестовый экземпляр а также, используемый JUnit Jupiter.

Спасибо за ценное объяснение, поэтому я собираюсь перейти к JUnit 5. Вы помните, когда я создавал проблему с JUnit 5 в Github? Я поделился там некоторым кодом о моих собственных экспериментах по миграции, и для "Parameterized" больше не было необходимости использовать SpringClassRule и SpringMethodRule. Теперь, если моя память меня не подводит, TestRule больше не существует в JUnit 5.

Manuel Jordan 12.03.2018 17:52

Другие вопросы по теме