@Autowired или конструктор вводят неуправляемые классы в контекст Spring @Service для лучшего тестирования

#java #spring #spring-boot #unit-testing

#Ява #весна #пружинный ботинок #модульное тестирование

Вопрос:

В проекте Spring Boot мы получаем доступ к нашим неуправляемым классам DAO с помощью статического метода:

 MyDao myDao = DaoProvider.getMyDao();  

Мы используем это в весенних управляемых @Service классах:

 @Service public class MyService {    public void foo() {  MyDao myDao = DaoProvider.getMyDao();  myDao.bar();  ....  } }  

Это затрудняет написание модульных тестов. Статические насмешки-это не вариант, потому что они замедляют наш конвейер сборки.

Мы предпочли бы иметь решение с @Autowired зависимостью от конструктора или с какой-либо конфигурацией, которая решает, какой класс вводить:

 @Service public class MyService {    @Autowired  MyDao myDao;    public void foo() {  myDao.bar();  ....  } }  

Очевидно, кто-то должен сказать Spring, какой класс вводить, потому MyDao что нет управляемого компонента Spring. Есть ли способ сделать это?:

 @Configuration public class NonManagedSpringInjectionConfiguration {    @Bean  MyDao getMyDao() {  return DaoProvider.getMyDao();  } }  

Комментарии:

1. Что вы имеете в виду под someone has to tell Spring what class to inject этим ? Spring автоматически вводит все, если @Autowire, @Service и @Bean используются правильно

2. MyDao-это не управляемый боб с пружиной. Так что Весна не сможет обнаружить его из коробки. Спасибо за подсказку, я отредактировал вопрос.

3. Вы решили свою проблему?

4. Да, спасибо, что спросили. Я не знал, что вы можете в значительной степени зарегистрировать любой класс в качестве компонента, как описано в варианте 2 в принятом ответе.

Ответ №1:

Вариант 1

Если вы не хотите превращать свой MyDao компонент в управляемый пружиной компонент, ваш более простой и, вероятно, лучший вариант-вместо этого создать MyService управляемый пружиной компонент программно, а не полагаться на @Service аннотации. Во-первых, просто удалите @Service из MyService и настройте его конструктор так, чтобы он принимал MyDao :

 public class MyService {   MyDao myDao;   public MyService(MyDao myDao) {  this.myDao = myDao;  }    public void foo() {  myDao.bar();  ....  } }  

И теперь вам просто нужно зарегистрировать MyService компонент, используемый @Bean в классе конфигурации, следующим образом:

 @Configuration public class WhateverConfiguration {    @Bean  MyService myService() {  return new MyService(DaoProvider.getMyDao());  } }  

Вариант 2

Если вместо этого есть возможность создать MyDao управляемый пружиной боб, просто сохраните NonManagedSpringInjectionConfiguration его как есть:

 @Configuration public class NonManagedSpringInjectionConfiguration {    @Bean  MyDao getMyDao() {  return DaoProvider.getMyDao();  } }  

Но тогда полагайтесь на инъекцию конструктора, а не на @Autowired . Это MyService облегчает модульное тестирование, а также явно определяет, что MyDao является обязательным для MyService правильной работы. В этом случае вы бы сохранили @Service и полагались на Spring для его создания:

 @Service public class MyService {   MyDao myDao;   public MyService(MyDao myDao) {  this.myDao = myDao;  }   public void foo() {  myDao.bar();  ....  } }  

Ответ №2:

Вам просто нужно указать профиль, например :

 @Configuration public class NonManagedSpringInjectionConfiguration {    @Bean  @Profile("dev")  MyDao getMyDao() {  return DaoProvider.getMyDao();  } }