Я пытаюсь написать модульный тест для простого компонента, который используется в моей программе для проверки форм. Компонент аннотирован @Component
и имеет переменную класса, которая инициализируется с помощью
@Value("${this.property.value}") private String thisProperty;
Я хотел бы написать модульные тесты для методов проверки внутри этого класса, однако, если это возможно, я бы хотел сделать это без использования файла свойств. Мой аргумент заключается в том, что если значение, которое я извлекаю из файла свойств, изменится, я бы хотел, чтобы это не повлияло на мой тестовый пример. Мой тестовый пример проверяет код, который проверяет значение, а не само значение.
Есть ли способ использовать код Java внутри моего тестового класса, чтобы инициализировать класс Java и заполнить свойство Spring @Value внутри этого класса, а затем использовать его для тестирования?
Я нашел это How To , кажется, близко, но все еще использует файл свойств. Я бы предпочел, чтобы это был код Java.
источник
Ответы:
Если возможно, я бы попытался написать эти тесты без Spring Context. Если вы создадите этот класс в своем тесте без пружины, то у вас будет полный контроль над его полями.
Для установки
@value
поля вы можете использовать пружиныReflectionTestUtils
- у него есть методsetField
для установки приватных полей.@see JavaDoc: ReflectionTestUtils.setField (java.lang.Object, java.lang.String, java.lang.Object)
источник
org.springframework.test.util.ReflectionTestUtils.setField(classUnderTest, "field", "value");
@Value
аннотацию в параметр конструктора. Это значительно упрощает тестовый код при написании кода вручную, и Spring Boot это не волнует.Начиная с Spring 4.1, вы можете устанавливать значения свойств только в коде, используя
org.springframework.test.context.TestPropertySource
аннотацию на уровне класса Unit Tests. Вы можете использовать этот подход даже для внедрения свойств в зависимые экземпляры bean-компонентов.Например
Примечание: необходимо иметь экземпляр
org.springframework.context.support.PropertySourcesPlaceholderConfigurer
в контексте SpringEdit 24-08-2017: Если вы используете SpringBoot 1.4.0 , а затем вы можете инициализировать тесты с
@SpringBootTest
и@SpringBootConfiguration
аннотаций. Больше информации здесьВ случае SpringBoot у нас есть следующий код
источник
Не злоупотребляйте приватными полями.
Использование рефлексии, как это делается в нескольких ответах, - это то, чего мы могли бы избежать.
Это приносит небольшую ценность здесь, в то время как это имеет много недостатков:
@Value String field
. Завтра вы можете объявить5
или10
о них в этом классе, и вы можете даже не знать, что вы уменьшаете дизайн класса. При более наглядном подходе к установке этих полей (например, конструктора) вы дважды подумаете, прежде чем добавлять все эти поля, и, вероятно, вы инкапсулируете их в другой класс и используете@ConfigurationProperties
.Сделайте свой класс тестируемым как единым, так и интеграционным
Чтобы иметь возможность писать как простые модульные тесты (то есть без работающего контейнера Spring), так и интеграционные тесты для вашего класса компонентов Spring, вы должны сделать этот класс пригодным для использования с Spring или без него.
Запуск контейнера в модульном тесте, когда он не требуется, является плохой практикой, которая замедляет локальные сборки: вы этого не хотите.
Я добавил этот ответ, потому что ни один ответ здесь, кажется, не показывает это различие, и поэтому они систематически полагаются на работающий контейнер.
Поэтому я думаю, что вы должны переместить это свойство, определенное как внутреннее свойство класса:
в параметр конструктора, который будет вставлен Spring:
Пример юнит-теста
Вы можете создать экземпляр
Foo
без Spring и ввести любое значениеproperty
благодаря конструктору:Пример интеграционного теста
Вы можете внедрить свойство в контекст с Spring Boot таким простым способом благодаря
properties
атрибуту@SpringBootTest
:Вы можете использовать в качестве альтернативы,
@TestPropertySource
но он добавляет дополнительную аннотацию:С Spring (без Spring Boot) все должно быть немного сложнее, но поскольку я долгое время не использовал Spring без Spring Boot, я не предпочитаю говорить глупости.
В качестве примечания: если у вас есть много
@Value
полей для установки, извлечение их в класс, помеченный с помощью@ConfigurationProperties
, более актуально, потому что мы не хотим конструктор с слишком большим количеством аргументов.источник
final
, т.е.private String final property
Если вы хотите, вы все равно можете запустить свои тесты в Spring Context и установить необходимые свойства в классе конфигурации Spring. Если вы используете JUnit, используйте SpringJUnit4ClassRunner и определите выделенный класс конфигурации для ваших тестов следующим образом:
Тестируемый класс:
Тестовый класс:
И класс конфигурации для этого теста:
Сказав это, я бы не рекомендовал этот подход, я просто добавил его сюда для справки. На мой взгляд, гораздо лучше использовать Mockito Runner. В этом случае вы вообще не запускаете тесты внутри Spring, что намного проще и понятнее.
источник
Это, кажется, работает, хотя все еще немного многословно (я хотел бы кое-что более короткое все еще):
источник
@TestProperty
аннотацию.@Value
s, независимо от того, установлено соответствующее свойство или нет.Добавление PropertyPlaceholderConfigurer в конфигурации работает для меня.
И в тестовом классе
источник