有没有办法在 Junit5 的另一个方法中模拟私有方法调用
Is there any way to Mock private method call inside another method in Junit5
下面是我想测试的方法,但据我所知,Junit5 不支持 PowerMockito。那么有什么方法可以在另一个方法中模拟私有方法调用吗?
public Class MyClass {
private void sendEmailNotification(Checklist Checklist){
EmailService emailService = new EmailService();
BaseDTO esDO = newFolderService.getFolderByUri(ServicesUtils.getDecodedCaseNodeUriFromSelfLink(Checklist.getEs_uri()));
String esName = esDO.getName();
SharedInfo sharedInfo = Checklist.getShared_info();
sharedInfo.setEng_space_name(esName);
String reviewer = Checklist.getReviewer();
String ChecklistUri = Checklist.getUri();
String ChecklistName = Checklist.getName();
String targetPhase = Checklist.getTarget_phase();
String comment = Checklist.getComment();
String submitter = Checklist.getSubmitter();
String appURL = Checklist.getShared_info().getApp_url();
String ChecklistLink = buildChecklistURL(appURL, ChecklistUri);
String emailBodyTemplate;
String emailSubject;
emailBodyTemplate = EmailTemplates.getEmailTemplateByName(EmailConstants.TEMPLATE_DELIVERABLE_ACCEPTED_REJECTED_WITH_COMMENTS);
emailSubject = String.format(EmailConstants.ACCEPT_REJECT_WITH_COMMENTS_SUBJECT, ChecklistName, targetPhase);
emailBodyTemplate = EmailTemplates.replaceSharedVariable(emailBodyTemplate, sharedInfo);
emailBodyTemplate = EmailTemplates.replaceVariable(emailBodyTemplate, EmailConstants.VAR_TARGET_PHASE, targetPhase);
emailBodyTemplate = EmailTemplates.replaceVariable(emailBodyTemplate, EmailConstants.VAR_REVIEWER, reviewer);
emailBodyTemplate = EmailTemplates.replaceVariable(emailBodyTemplate, EmailConstants.VAR_CHECKLIST_ITEM_NAME, ChecklistName);
emailBodyTemplate = EmailTemplates.replaceVariable(emailBodyTemplate, EmailConstants.VAR_COMMENT, comment);
emailBodyTemplate = EmailTemplates.replaceVariable(emailBodyTemplate, EmailConstants.VAR_CHECKLIST_ITEM_URL, ChecklistLink);
try {
emailService.sendEmail(submitter, EmailConstants.EMAIL_SENDER, emailSubject, emailBodyTemplate);
} catch (RuntimeException e) {
Checklist.addError(messages.get(E_ACCEPT_REJECT_SEND_EMAIL));
}
}
//Method to be tested
public void method(Checklist checklist){
/*Some Code*/
sendEmail(checklist); /* want to ignore this, as throwing NullPointerException*/
/*Some Code*/
}}
你是对的。 Powermock 尚不支持 JUnit 5,并且在其官方 github 存储库 here.
中存在未解决的问题
似乎没有任何简单的方法可以使用 Junit5 runner 来模拟私有方法,除非您当然决定使用自定义类加载器并进行字节码操作。
但是,我建议您不要模拟整个方法,而是模拟用于发送电子邮件的依赖项(除非该依赖项使用某种最终方法)。
如果你连那个都做不到,那么最好的方法是使用 Junit4 而不是 Junit5。
我建议将 private
方法的范围更改为 package
或 protected
。然后,您可以在扩展 class.
的测试 class 中覆盖它
我不会尝试模拟 sendMail
方法中使用的所有服务,因为您的测试将依赖于 sendMail
方法中的所有内容,即使它不需要它。因此,只要 sendMail
方法的内部发生变化,就必须更改您的测试。这会很糟糕,因为您的测试不需要 sendMail
方法 - 这就是您想要模拟它的原因。
你的测试也将变得非常复杂,所有的模拟都是使 sendMail
方法工作所必需的。
更好的方法是将 sendMail 方法提取到一个接口中,并使用当前 sendMail 方法的内容创建一个实现。
public interface ChecklistNotifier {
public void sendNotification(Checklist checklist);
}
public class EmailChecklistNotifier implements ChecklistNotifier {
public void sendNotification(Checklist checklist){
EmailService emailService = new EmailService();
BaseDTO esDO = newFolderService.getFolderByUri(ServicesUtils.getDecodedCaseNodeUriFromSelfLink(Checklist.getEs_uri()));
// ...
}
}
您的客户 class 然后可以使用 ChecklistNotifier
.
public class ClientClass {
private ChecklistNotifier notifier;
public ClientClass(ChecklistNotifier notifier){
this.notifier = notifier;
}
public void method(Checklist checklist){
/*Some Code*/
notifier.sendnotification(checklist);
/*Some Code*/
}}
}
现在您可以轻松地在测试中创建一个 ClientClass
实例并将其传递给一个 ChecklistNotifier
模拟或只是一个简单的实现。
这种方法也尊重 SOLID 原则,因为你有
ClientClass
和 EmailChecklistNotifier
的单一责任
- 使其打开-关闭 - 您可以将其替换为模拟或其他实现,也许是短信通知
- 隔离界面 - ChecklistNotification
- 反转依赖关系,从而将
ClientClass
从邮件发送实现依赖关系中分离出来。
下面是我想测试的方法,但据我所知,Junit5 不支持 PowerMockito。那么有什么方法可以在另一个方法中模拟私有方法调用吗?
public Class MyClass {
private void sendEmailNotification(Checklist Checklist){
EmailService emailService = new EmailService();
BaseDTO esDO = newFolderService.getFolderByUri(ServicesUtils.getDecodedCaseNodeUriFromSelfLink(Checklist.getEs_uri()));
String esName = esDO.getName();
SharedInfo sharedInfo = Checklist.getShared_info();
sharedInfo.setEng_space_name(esName);
String reviewer = Checklist.getReviewer();
String ChecklistUri = Checklist.getUri();
String ChecklistName = Checklist.getName();
String targetPhase = Checklist.getTarget_phase();
String comment = Checklist.getComment();
String submitter = Checklist.getSubmitter();
String appURL = Checklist.getShared_info().getApp_url();
String ChecklistLink = buildChecklistURL(appURL, ChecklistUri);
String emailBodyTemplate;
String emailSubject;
emailBodyTemplate = EmailTemplates.getEmailTemplateByName(EmailConstants.TEMPLATE_DELIVERABLE_ACCEPTED_REJECTED_WITH_COMMENTS);
emailSubject = String.format(EmailConstants.ACCEPT_REJECT_WITH_COMMENTS_SUBJECT, ChecklistName, targetPhase);
emailBodyTemplate = EmailTemplates.replaceSharedVariable(emailBodyTemplate, sharedInfo);
emailBodyTemplate = EmailTemplates.replaceVariable(emailBodyTemplate, EmailConstants.VAR_TARGET_PHASE, targetPhase);
emailBodyTemplate = EmailTemplates.replaceVariable(emailBodyTemplate, EmailConstants.VAR_REVIEWER, reviewer);
emailBodyTemplate = EmailTemplates.replaceVariable(emailBodyTemplate, EmailConstants.VAR_CHECKLIST_ITEM_NAME, ChecklistName);
emailBodyTemplate = EmailTemplates.replaceVariable(emailBodyTemplate, EmailConstants.VAR_COMMENT, comment);
emailBodyTemplate = EmailTemplates.replaceVariable(emailBodyTemplate, EmailConstants.VAR_CHECKLIST_ITEM_URL, ChecklistLink);
try {
emailService.sendEmail(submitter, EmailConstants.EMAIL_SENDER, emailSubject, emailBodyTemplate);
} catch (RuntimeException e) {
Checklist.addError(messages.get(E_ACCEPT_REJECT_SEND_EMAIL));
}
}
//Method to be tested
public void method(Checklist checklist){
/*Some Code*/
sendEmail(checklist); /* want to ignore this, as throwing NullPointerException*/
/*Some Code*/
}}
你是对的。 Powermock 尚不支持 JUnit 5,并且在其官方 github 存储库 here.
中存在未解决的问题似乎没有任何简单的方法可以使用 Junit5 runner 来模拟私有方法,除非您当然决定使用自定义类加载器并进行字节码操作。
但是,我建议您不要模拟整个方法,而是模拟用于发送电子邮件的依赖项(除非该依赖项使用某种最终方法)。
如果你连那个都做不到,那么最好的方法是使用 Junit4 而不是 Junit5。
我建议将 private
方法的范围更改为 package
或 protected
。然后,您可以在扩展 class.
我不会尝试模拟 sendMail
方法中使用的所有服务,因为您的测试将依赖于 sendMail
方法中的所有内容,即使它不需要它。因此,只要 sendMail
方法的内部发生变化,就必须更改您的测试。这会很糟糕,因为您的测试不需要 sendMail
方法 - 这就是您想要模拟它的原因。
你的测试也将变得非常复杂,所有的模拟都是使 sendMail
方法工作所必需的。
更好的方法是将 sendMail 方法提取到一个接口中,并使用当前 sendMail 方法的内容创建一个实现。
public interface ChecklistNotifier {
public void sendNotification(Checklist checklist);
}
public class EmailChecklistNotifier implements ChecklistNotifier {
public void sendNotification(Checklist checklist){
EmailService emailService = new EmailService();
BaseDTO esDO = newFolderService.getFolderByUri(ServicesUtils.getDecodedCaseNodeUriFromSelfLink(Checklist.getEs_uri()));
// ...
}
}
您的客户 class 然后可以使用 ChecklistNotifier
.
public class ClientClass {
private ChecklistNotifier notifier;
public ClientClass(ChecklistNotifier notifier){
this.notifier = notifier;
}
public void method(Checklist checklist){
/*Some Code*/
notifier.sendnotification(checklist);
/*Some Code*/
}}
}
现在您可以轻松地在测试中创建一个 ClientClass
实例并将其传递给一个 ChecklistNotifier
模拟或只是一个简单的实现。
这种方法也尊重 SOLID 原则,因为你有
ClientClass
和EmailChecklistNotifier
的单一责任
- 使其打开-关闭 - 您可以将其替换为模拟或其他实现,也许是短信通知
- 隔离界面 - ChecklistNotification
- 反转依赖关系,从而将
ClientClass
从邮件发送实现依赖关系中分离出来。