#java #spring #junit
#java #spring #junit
Вопрос:
Ситуация: у меня есть класс реализации сервиса с аннотацией @Service с доступом к файлу свойств.
@Service("myService")
public class MySystemServiceImpl implements SystemService{
@Resource
private Properties appProperties;
}
Объект свойств настраивается через конфигурационный файл. applicationContext.xml
<util:properties id="appProperties" location="classpath:application.properties"/>
Я хочу протестировать некоторые методы этой реализации.
Вопрос: Как получить доступ к MySystemServiceImpl-объекту из тестового класса таким образом, чтобы свойства appProperties были инициализированы должным образом?
public class MySystemServiceImplTest {
//HOW TO INITIALIZE PROPERLY THROUGH SPRING?
MySystemServiceImpl testSubject;
@Test
public void methodToTest(){
Assert.assertNotNull(testSubject.methodToTest());
}
}
Я не могу просто создать новый MySystemServiceImpl — методы, которые используют appProperties, вызывают исключение NullPointerException. И я не могу напрямую вводить свойства в объект — нет подходящего метода установки.
Просто укажите правильные шаги здесь (спасибо @NimChimpsky за ответ):
-
Я скопировал application.properties в раздел test /resources.
-
Я скопировал applicationContext.xml в стадии тестирования / реж. ресурсов. В контексте приложения я добавляю новый компонент (определение свойств приложения уже здесь):
<bean id="testSubject" class="com.package.MySystemServiceImpl">
-
Я модифицировал тестовый класс таким образом:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={"/applicationContext.xml"}) public class MySystemServiceImplTest { @Autowired MySystemServiceImpl testSubject; }
-
И это делает трюк — теперь в моем тестовом классе доступен полностью функциональный объект
Ответ №1:
В качестве альтернативы, чтобы выполнить интеграционный тест, я делаю это.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"/applicationContext-test.xml"})
@Transactional
public class MyTest {
@Resource(name="myService")
public IMyService myService;
Затем используйте сервис, как обычно. Добавьте контекст приложения в свой каталог test / resources
Ответ №2:
Просто используйте его конструктор :
MySystemServiceImpl testSubject = new MySystemServiceImpl();
Это модульный тест. Модульный тест проверяет класс изолированно от других классов и инфраструктуры.
Если ваш класс имеет зависимости от других интерфейсов, смоделируйте эти интерфейсы и создайте объект с этими макетами в качестве аргумента. В этом весь смысл внедрения зависимостей: возможность вводить другие, фиктивные реализации внутри объекта, чтобы легко протестировать этот объект.
Редактировать:
Вы должны предоставить сеттер для вашего объекта properties, чтобы иметь возможность вводить нужные свойства для каждого из модульных тестов. Введенные свойства могут содержать номинальные значения, экстремальные значения или неправильные значения в зависимости от того, что вы хотите протестировать. Внедрение полей практично, но плохо сочетается с модульным тестированием. При модульном тестировании предпочтительнее использовать инъекцию конструктора или установщика, поскольку основная цель внедрения зависимостей заключается именно в том, чтобы иметь возможность вводить фиктивные или конкретные зависимости в модульные тесты.
Комментарии:
1. К сожалению, у меня нет возможности изменять класс. Вот почему я должен придерживаться Spring injection. Во всем остальном я согласен с вашей точкой зрения
2. Есть ли какой-либо недостаток в том, чтобы не вводить?