@SpringBootTest does not autowire JavaMailSender and throws error
Asked Answered
S

7

10

What am I doing wrong here? My understanding is Spring should autowire JavaMailSender the way its autowiring EventRepository. Any guidance?

application.properties and application-test.properties

mail.host='smtp.gmail.com' -
mail.port=587
mail.username=username
mail.password=password
mail.properties.mail.smtp.starttls.enable=true

My Implementation class : This works fine if I run my application

      @Service
            public class EventService {
             private EventRepository eventRepository;
             private JavaMailSender javaMailSender;

                public EventService(EventRepository eventRepository, JavaMailSender   javaMailSender) {
                    this.eventRepository = eventRepository;
                    this.javaMailSender = javaMailSender;
                }

                public Event send(Event event) {
                   SimpleMailMessage message = new SimpleMailMessage();
                    message.setText("");
                    message.setSubject("");
                    message.setTo("");
                    message.setFrom("");
                    javaMailSender.send(message);
                    return eventRepository.save(event);
                }

            }

My Integration Test class : Able to Autowired EventRepository but not JavaMailSender.

       @RunWith(SpringRunner.class)
        @SpringBootTest
        public class ApplicationIntegrationTests {
            @Autowired
            private EventService eventService;

         @Test
            public void test() throws Exception {
                eventService.save(new Event());
        }

        }

ERROR:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.mail.javamail.**JavaMailSender**' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
            at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1486)
Smail answered 5/3, 2017 at 14:5 Comment(0)
F
3

Please make sure that your test reside in the same package as your main @SpringBootApplication class.

for example if @SpringBootApplication class is in src/main/java/some/package then your @SpringBootTest need to be in src/test/java/some/package. If it is not, you need to explicitly set @ComponentScan to include some.package. You can also use @SpringBootTest(classes=...), @ContextConfiguration(classes=...)}.

You can also put a @SpringBootConfiguration class in your test package that scans for your main package.

Friel answered 6/3, 2017 at 14:57 Comment(2)
Did you managed to resolve this issue? I am having the same problem.Brandonbrandt
check : github.com/spring-projects/spring-boot/issues/… and codesd.com/item/….Smail
F
2

In my case that was caused by difference in application.properties files in main and test resources.

Following properties were missing in test file:

spring.mail.host=<my host>
spring.mail.port=<my port>
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.connectiontimeout=5000
spring.mail.properties.mail.smtp.timeout=3000
spring.mail.properties.mail.smtp.writetimeout=5000

Please note that it is not best idea to use external services in unit tests.

Flagstad answered 20/9, 2018 at 9:9 Comment(0)
K
2

You should define one of the properties spring.mail.host or spring.mail.jndi-name for spring autoconfiguration or define your own bean in your config class.

Check this class org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration for details.

Example:

@Service
public class MyEmailService {

    @Autowired
    private JavaMailSender mailSender;

}
import org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration;

@RunWith(SpringRunner.class)
@SpringBootTest(
   properties = "spring.mail.host=localhost", // <--- inlined property
   classes = {MyEmailService.class, MailSenderAutoConfiguration.class}
)
public class MyEmailServiceTest {

    @Autowired
    private MyEmailServiceTest emailService;

    @Autowire 
    private JavaMailSender javaMailSender; // if you need

    @Test
    public void validEmails() {
        // some tests of emailService
    }
}
Karlin answered 29/1, 2021 at 13:14 Comment(1)
Thanks man, this works even without @SpringRunner. the key here is to include the AutoConfiguration classes, in my case I had to add ThymeleafAutoConfiguration as well, as I use Thymeleaf as the template engine.Broody
S
0

Autowire Rule: The are only two, i said ONLY TWO possibility for Autowiring to throw null.

  1. You manually created Object using NEW keyword. In IoC framework environment you should let the framwork do it's shit.

for example private AnyMailSender mail = new AnyMailSender()

  1. Some Object might been left Non-Autowired. In you case you are not Autowiring this line

private JavaMailSender javaMailSender;

You should do something like this

@Autowire private JavaMailSender javaMailSender;

Sparkle answered 23/8, 2019 at 6:41 Comment(0)
C
0

Your need to create a bean. Just like below in your configuration package(if you have).

@Bean
public JavaMailSender getJavaMailSender() {
    JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
    mailSender.setHost("smtp.gmail.com");
    mailSender.setPort(587);
    
    mailSender.setUsername("[email protected]");
    mailSender.setPassword("password");
    
    Properties props = mailSender.getJavaMailProperties();
    props.put("mail.transport.protocol", "smtp");
    props.put("mail.smtp.auth", "true");
    props.put("mail.smtp.starttls.enable", "true");
    props.put("mail.debug", "true");
    
    return mailSender;
}

And put @Configuration annotation above the class

Ciel answered 27/3, 2021 at 6:14 Comment(0)
D
0

Make sure the SpringBoot class and the Test class have the same package name

Drusilla answered 2/7, 2021 at 4:49 Comment(0)
L
0

Your object should be configured properly.
Use 'JavaMailSenderImpl' instead of that, Declare your @Bean with any of the following ways,

@Autowired
private JavaMailSenderImpl mailSender;

Or

JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
Lorrettalorri answered 2/7, 2021 at 9:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.