【问题标题】:Is there any way to Mock private method call inside another method in Junit5有没有办法在 Junit5 中的另一个方法中模拟私有方法调用
【发布时间】:2020-07-10 18:23:23
【问题描述】:

以下是我想测试的方法,但据我所知 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*/

}}

【问题讨论】:

标签: java junit5 powermockito


【解决方案1】:

我建议将private 方法的范围更改为packageprotected。然后,您可以在扩展您的类的测试类中覆盖它。

我不会尝试模拟 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()));
    // ...
  }
}

然后您的客户端类可以使用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与邮件发送实现依赖关系解耦。

【讨论】:

    【解决方案2】:

    你是对的。 Powermock 尚不支持 JUnit 5,在其官方 github 存储库 here 中有一个未解决的问题。

    似乎没有任何简单的方法可以使用 Junit5 runner 来模拟私有方法,除非您当然决定使用自定义类加载器并进行字节码操作。

    但是,我建议您模拟用于发送电子邮件的依赖项,而不是模拟整个方法(除非该依赖项使用某种最终方法)。

    如果你连这个都做不到,那么最好的方法是使用 Junit4 而不是 Junit5。

    【讨论】:

    • 你可以根据需要使用 Spy 模拟方法
    • 但是由于它是私有的,您可以将其更改为受保护的,以便您可以在测试包中访问它
    • 由于某种原因,我无法将类方法更改为受保护的,我从 Junit 或 Spring 听说过 ReflectionUtils,但不确定这是否有帮助,在这种情况下,我只想让这个方法什么都不做,任何关于这是否可能的线索?
    • @Baljinder ReflectionUtils 不用于模拟。它是一个简单的实用程序类,用于使用反射 API 和处理反射异常。 您是否尝试过模拟用于发送电子邮件的依赖项(正如我在回答中所建议的那样)?你能告诉我们那个 sendEmail 方法吗?
    • 您好@AbhinabaChakraborty,请找到发送电子邮件的方法。在模拟 emailService 后它工作了,感谢您的帮助
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-03
    • 2010-09-26
    • 1970-01-01
    • 1970-01-01
    • 2019-06-12
    • 2021-08-31
    • 1970-01-01
    相关资源
    最近更新 更多