运行单元测试时出现Spring Boot错误

时间:2017-02-16 09:04:35

标签: java spring email spring-boot

差不多8年之后,我不得不把我的春天知识弄清楚,只要我不必编写单元测试,事情就会很好。我有以下单元测试来测试我的一个服务,当我尝试运行它时,它将失败并显示:

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);
            }
        });
    }
}

如何编写单元测试,以便注入/自动连接我的服务?

2 个答案:

答案 0 :(得分:0)

您在测试中使用了一个带有弹簧启动测试的@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
    }

}

答案 1 :(得分: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)