2017-02-16 17 views
0

После почти 8 лет, я должен очистить свои знания от Spring, и все было хорошо, пока мне не приходилось писать модульные тесты. У меня есть следующий модульный тест, который будет проверить один из моей службы, и когда я попытался запустить его, он потерпит неудачу с:Ошибка при загрузке весны при тестировании блока

org.springframework.beans.factory.UnsatisfiedDependencyException 

и не в состоянии решить эту услугу eMailNotificationService!

Так вот мой тест Раздел:

@ActiveProfiles("test") 
@ComponentScan(basePackages = {"com.middleware.service.email", "it.ozimov.springboot.templating.mail"}) 
@RunWith(SpringRunner.class) 
public class EMailNotificationServiceTest { 

    @Autowired() 
    private EMailNotificationService eMailNotificationService; 

    @MockBean(name = "emailService") 
    private EmailService emailService; 

    @Test 
    public void sendResetPasswordEMailNotification() { 

     System.out.println(eMailNotificationService); 

     // TODO: complete the test 
    } 
} 

EMailNotificationService, как показано ниже, и это определено в пакете com.middleware.service.email:

@Service() 
@Scope("singleton") 
public class EMailNotificationService { 

    private static Log logger = LogFactory.getLog(EMailNotificationService.class); 

    @Value("${service.email.sender}") 
    String senderEMail; 

    @Value("${service.email.sender.name}") 
    String senderName; 

    @Value("${service.email.resetPassword.link}") 
    String resetPasswordLink; 

    @Autowired 
    public EmailService emailService; 

    public void sendResetPasswordEMail(List<EMailUser> userList) { 
     List<String> allEMails = userList.stream() 
            .map(EMailUser::getUserEMail) 
            .collect(Collectors.toList()); 
     userList.stream().forEach(emailUser -> { 
      final Email email; 
      try { 
       email = DefaultEmail.builder() 
         .from(new InternetAddress(senderEMail, senderName)) 
         .to(Lists.newArrayList(new InternetAddress(emailUser.getUserEMail(), emailUser.getUserName()))) 
         .subject("Reset Password") 
         .body("")//Empty body 
         .encoding(String.valueOf(Charset.forName("UTF-8"))).build(); 

       // Defining the model object for the given Freemarker template 
       final Map<String, Object> modelObject = new HashMap<>(); 
       modelObject.put("name", emailUser.getUserName()); 
       modelObject.put("link", resetPasswordLink); 

       emailService.send(email, "resetPasswordEMailTemplate.ftl", modelObject); 
      } catch (UnsupportedEncodingException | CannotSendEmailException ex) { 
       logger.error("error when sending reset password EMail to users " + allEMails, ex); 
      } 
     }); 
    } 
} 

Как я пишу единичный тест, чтобы мой сервис был инъецирован/автоуведомлен?

+0

возможно, что этот компонент не создан для вашего профиля 'контрольная работа'? – wawek

ответ

0

Вы использовали в своем тесте аннотацию @MockBean, которая поставляется с испытанием на весеннюю загрузку. Следовательно, если вы полагаетесь на функции, которые предоставляет Spring-Boot-Test, вы должны пометить свой тест аннотацией @SpringBootTest (в этом случае вы также можете удалить аннотацию @ComponentScan). Следовательно, весна будет правильно издеваться над вашими зависимостями (EmailService) и предоставит вам компонент EmailNotificationService.

Дополнительная информация о тестировании загрузки пружины, которая может оказаться полезной, можно найти в их справочной документации: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html

Update:

Такие тесты воспитывают весь контекст, который может быть ненужным и подходит скорее интеграционные тесты, а не модульные тесты. Для «чистых» модульных тестов вы можете забыть, что вы тестируете весенние службы и относитесь к своим классам как POJO. В этом случае вы можете использовать Mockito для издевательства над вашими зависимостями (кстати, с весенним загрузочным тестом). Вы можете переписать код следующим образом:

@RunWith(MockitoJUnitRunner.class) 
public class EMailNotificationServiceTest { 

    @InjectMocks 
    private EmailNotService eMailNotificationService; 

    @Mock 
    private EmailService emailService; 

    @Before 
    public void setup() { 
     eMailNotificationService.setSenderEMail("myemail"); 
     // set other @Value fields 
    } 

    @Test 
    public void sendResetPasswordEMailNotification() { 
     System.out.println(eMailNotificationService); 
     // TODO: complete the test 
    } 

} 
+0

Использование аннотации @SpringBootTest загружает все мое приложение, прямо из создания сопоставления Hibernate, создания экземпляров других сервисов и т. Д., На которых я действительно не хочу. Эта служба электронной почты написана в полной изоляции. У него нет никаких зависимостей или вообще что бы спячки. Итак, как я могу создать экземпляр этой службы и протестировать ее? – sparkr

+0

Закрыть, но не достаточно! Мне все еще нужны значения для других полей, таких как senderEMail, senderName, resetPasswordLink. Так я тоже издеваюсь над этим? И это уже отвратительно держать насмешливые ценности для моих частных полей. – sparkr

+0

@sparkr в '@ SpringBootTest' вы можете установить класс конфигурации (через arg classes =" your.class "). В этом классе, отмеченном как '@ TestConfiguration', вы можете исключить все ненужные конфигурации с помощью' @EnableAutoConfiguration (exclude = {DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class, ...}) ' – rvit34

0

Я предпочитаю использовать эту конструкции:

public static void manuallyInject(String fieldName, Object instance, Object targetObject) 
     throws NoSuchFieldException, IllegalAccessException { 
    Field field = instance.getClass().getDeclaredField(fieldName); 
    field.setAccessible(true); 
    field.set(instance, targetObject); 
} 

в вашем случае: manuallyInject("eMailNotificationService", emailService, eMailNotificationService)