差不多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);
}
});
}
}
如何编写单元测试,以便注入/自动连接我的服务?
答案 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)