运行单元测试时出现弹簧启动错误
经过近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);
}
});
}
}
我怎样写我的单元测试,使我的服务注入/自动装配?
您在测试中使用了一个@MockBean注释,它附带了一个弹簧引导测试。因此,如果您依赖的是spring-boot-test提供的功能,则必须使用@SpringBootTest注释标记测试(在这种情况下,您还可以移除@ComponentScan注释)。因此,spring会正确地模拟你的依赖关系(EmailService)并且会为你提供EmailNotificationService bean。
关于春天开机测试的更多信息,可能是有用的可以自己参考文档中找到:https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html
更新:
这样的测试带来了整个背景下可能是不必要的和适合宁可集成测试而不是单元测试。对于'纯粹'单元测试,你可以忘记你正在测试spring服务,并将你的类作为POJO处理。在这种情况下,你可以使用Mockito来嘲笑你的依赖(这是btw自带的spring-boot-test)。您可以通过以下方式重写代码:
@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
}
}
使用@SpringBootTest注解将加载整个我的应用程序,从创建Hibernate映射,实例化其他服务等等,我实际上不需要。此电子邮件服务完全隔离编写。它没有任何依赖或任何休眠。那么我怎么才能实例化这个服务并测试它呢? – sparkr
关闭,但还不够!我仍然需要其他字段的值,如senderEMail,senderName,resetPasswordLink。那么我也嘲笑这一点吗?这对于我的私人领域嘲笑价值已经有点恶心了。 – sparkr
@sparkr在'@SpringBootTest'中可以设置配置类(通过arg classes =“your.class”)。在那个类中,标记为'@ TestConfiguration',你可以通过'@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class,HibernateJpaAutoConfiguration.class,...})排除所有不需要的配置' – rvit34
我更喜欢使用这种结构:
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)
是有可能,是不是为您的配置文件创建这个bean '测试'? – wawek