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)
T D
  • 1,080
  • 2
  • 13
  • 20

7 Answers7

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.

Tom
  • 3,711
  • 2
  • 25
  • 31
  • 1
    Did you managed to resolve this issue? I am having the same problem. – mismas May 15 '17 at 14:42
  • check : https://github.com/spring-projects/spring-boot/issues/2876#issuecomment-96624625 and https://www.codesd.com/item/is-it-possible-to-autowire-the-configuration-of-a-spring-project-configuration-to-another-spring-project.html. – T D Mar 04 '18 at 14:08
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.

igor
  • 699
  • 1
  • 9
  • 26
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
    }
}
Sergey Nemchinov
  • 1,348
  • 15
  • 21
  • 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. – alegria Apr 22 '22 at 23:34
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;

HA S
  • 1,129
  • 12
  • 10
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("my.gmail@gmail.com");
    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

jeno
  • 62
  • 4
0

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

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();
Dhwanil Patel
  • 2,273
  • 1
  • 18
  • 28