问题
we are using Freemarker for generating the HTML code for the emails our application is going to be sending.
Our usage and configuration is based off of https://github.com/hdineth/SpringBoot-freemaker-email-send Particularly:
package com.example.techmagister.sendingemail.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ResourceLoader;
import org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean;
import java.io.IOException;
@Configuration
public class FreemarkerConfig {
@Bean(name="emailConfigBean")
public FreeMarkerConfigurationFactoryBean getFreeMarkerConfiguration(ResourceLoader resourceLoader) {
FreeMarkerConfigurationFactoryBean bean = new FreeMarkerConfigurationFactoryBean();
bean.setTemplateLoaderPath("classpath:/templates/");
return bean;
}
}
However, there is absolutely no information or documentation anywhere, about how to run Unit Tests for this using JUnit 5.
When I added the relevant dependencies
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
versions:
<junit.jupiter.version>5.3.1</junit.jupiter.version>
<mockito.version>2.23.0</mockito.version>
And made a test class:
package com.example.techmagister.sendingemail;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.Before;
import org.junit.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.io.IOException;
@ExtendWith({SpringExtension.class, MockitoExtension.class})
@Import(com.example.techmagister.sendingemail.config.FreemarkerConfig.class)
public class EmailTestTest {
private static final Logger LOGGER = LogManager.getLogger(EmailTestTest.class);
@Autowired
@Qualifier("emailConfigBean")
private Configuration emailConfig;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
@Test
public void test() throws Exception {
try {
Template template = emailConfig.getTemplate("email.ftl");
} catch (IOException e) {
e.printStackTrace();
}
}
}
When I run that in debug mode, emailConfig
is null.
Why is that?
Their test example https://github.com/hdineth/SpringBoot-freemaker-email-send/blob/master/src/test/java/com/example/techmagister/sendingemail/SendingemailApplicationTests.java works if I add the same autowired property, but it is a full SprintBoot context that is slow to boot, and I need to test just template usage, without actually sending out the email.
In our actual code (which is large, multi module project), I have another error org.springframework.beans.factory.UnsatisfiedDependencyException
caused by:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'freemarker.template.Configuration' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=emailConfigBean)}
But that is just for context, first I want to get it working in the simple, sample project then worry about getting it working in our complex one.
回答1:
You cannot autowire your emailConfigBean
directly as a freemarker.template.Configuration
FreeMarkerConfigurationFactoryBean
is a factorybean.
To get the Confuguration
you need to call factorybean.getObject()
so instead of
@Autowired
@Qualifier("emailConfigBean")
private Configuration emailConfig;
just autowire your factorybean FreeMarkerConfigurationFactoryBean
and load your template with emailConfig.getObject().getTemplate("email.ftl")
@Autowired
@Qualifier("emailConfigBean")
private FreeMarkerConfigurationFactoryBean emailConfig;
@Test
void testFreemarkerTemplate(){
Assertions.assertNotNull(emailConfig);
try {
Template template =
emailConfig
.getObject() // <-- get the configuration
.getTemplate("email.ftl"); // <-- load the template
Assertions.assertNotNull(template);
} catch (Exception e) {
e.printStackTrace();
}
working test on github
On the other hand...
In a Spring Boot application the Freemarker configuration can be simplified by using the spring-boot-starter-freemarker
dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
<version>1.5.6.RELEASE</version>
</dependency>
This starter for building MVC web applications using FreeMarker views adds the necessary auto-configuration. All you need to do is placing your template files in the resources/templates
folder.
Then you just can autowire the freemarkerConfig
(or use constructor injection):
@Autowired
private Configuration freemarkerConfig;
来源:https://stackoverflow.com/questions/59220213/unit-testing-freemarker-templates-in-springboot-unable-to-initialize-freemarke