有没有办法在 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 方法的范围更改为 packageprotected。然后,您可以在扩展 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 原则,因为你有

  • ClientClassEmailChecklistNotifier
  • 的单一责任
  • 使其打开-关闭 - 您可以将其替换为模拟或其他实现,也许是短信通知
  • 隔离界面 - ChecklistNotification
  • 反转依赖关系,从而将 ClientClass 从邮​​件发送实现依赖关系中分离出来。