Что это делает: @RunWith (SpringJUnit4ClassRunner.class)
Что делает эта аннотация?
Когда я хотел бы использовать это?
Когда бы я не хотел использовать это?
@RunWith(SpringJUnit4ClassRunner.class)
Я могу найти больше случаев использования этого, когда я Google и не могу найти объяснение 101 того, что эта аннотация должна сообщать мне или когда/почему я буду использовать это?
Ответы
Ответ 1
Аннотации используются для конфигурирования unit test, требующего инъекции зависимостей Spring.
От Spring Ссылка - 10. Тестирование узла:
10.1 Создание класса unit test
Чтобы unit test выполнял пакетное задание, среда должна загружать задание ApplicationContext. Для его запуска используются две аннотации:
@RunWith (SpringJUnit4ClassRunner.class): указывает, что класс должен использовать средства Spring JUnit.
@ContextConfiguration (locations = {...}): Указывает, какие файлы XML содержат ApplicationContext.
Ответ 2
Если вы используете аннотации, а не файлы XML, то в аннотацию @ContextConfiguration
должен быть включен любой класс, для которого вы проводите модульное тестирование, требующее внедрения зависимостей Spring. Например:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = FooManager.class)
class FooManagerTest {
@Autowired
FooManager fooManager;
Теперь, когда вы используете fooManager в модульном тесте, для него будет настроен контекст Spring.
Если fooManager автоматически подключается к каким-либо bean-компонентам, то эти классы bean-компонентов также должны быть в аннотации @ContextConfiguration
. Поэтому, если бин FooManager автоматически подключается к бину FooReporter:
@ContextConfiguration(classes = {FooManager.class, FooReporter.class})
Если bean-компоненты, которые fooManager автоматически связывают, содержат состояние, то вы, вероятно, захотите сбросить состояние этих bean-компонентов для каждого теста. В этом случае вы можете добавить аннотацию @DirtiesContext
к вашему тестовому классу:
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
Если fooManager или какой-либо из его компонентов с автопроводкой читает Spring config, то вам нужно добавить список инициализаторов в аннотацию @ContextConfiguration
, которая содержит класс ConfigFileApplicationContextInitializer:
@ContextConfiguration(classes = FooManager.class, initializers = ConfigFileApplicationContextInitializer.class)
Ответ 3
Чтобы ответить на вопрос, когда вы хотите и не хотите использовать это часть вопроса.
Когда использовать SpringJUnit4ClassRunner
IMO SpringJUnit4ClassRunner должен использоваться очень экономно. При запуске контейнера Spring для запуска модульного теста возникают значительные накладные расходы.
Обычно я использую SpringJUnit4ClassRunner для проверки:
- что компоненты вводятся (автоматически подключаются), как и ожидалось
- эти данные конфигурации вводятся как ожидалось
По крайней мере, у меня всегда есть простой тест SpringJUnit4ClassRunner для проверки работоспособности контейнера Spring. OK
При введении компонентов могут возникнуть проблемы, если аннотация @Qualifier
не используется или используется неправильно. Тест проверки работоспособности выявит такие проблемы.
При загрузке конфигурации из нескольких файлов yaml может потребоваться проверить, что карты объединяются, как ожидается, с соответствующими переопределениями.
Когда не следует использовать SpringJUnit4ClassRunner
Я бы не использовал SpringJUnit4ClassRunner для тестирования не связанных со Spring функций в тестируемом коде. Что по моему опыту означает большую часть функциональности.
Таким образом, это означает, что любые автоматически подключенные компоненты и введенные данные конфигурации должны быть проверены. Это может означать немного кода установки для ваших модульных тестов. Однако этот код установки нужно написать только один раз для всех тестов в тестируемом классе. Также гораздо быстрее запускать модульные тесты с проверенными компонентами.
Я продолжаю издеваться и использую Спока, чтобы высмеивать компоненты. Пример заводного кода:
import spock.lang.Specification
class FooManagerTest extends Specification {
FooManager cut
void createMockFooReporter() {
FooReporter mockFooReporter = Mock(FooReporter)
mockFooReporter.fooFormatter = Mock(FooFormatter)
}
void setup() {
cut = new FooManager()
cut.fooReporter = createMockFooReporter()
}
void "Basic test"() {
// Do a basic test using 'cut'
}
}
В этом примере у тестируемого класса FooManager
есть автопровод FooReporter
, который сам содержит автопровод FooFormatter
.