Есть ли способ имитировать вызов частного метода внутри другого метода в Junit5 - PullRequest
0 голосов
/ 10 июля 2020

Ниже приведен метод, который я хотел протестировать, но, насколько мне известно, 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*/

}}

Ответы [ 2 ]

2 голосов
/ 10 июля 2020

Вы правы. Powermock еще не поддерживает JUnit 5, и в их официальном репозитории github есть открытая проблема здесь .

Кажется, нет простого способа имитировать частные методы с помощью Junit5 runner, если только Конечно, вы решаете использовать собственный загрузчик классов и выполнять манипуляции с байт-кодом.

Однако вместо того, чтобы издеваться над всем методом, я предлагаю вам издеваться над зависимостью, которая используется для отправки электронного письма (если эта зависимость не использует окончательный метод).

А если вы даже не можете этого сделать, то лучше всего использовать Junit4 вместо Junit5.

0 голосов
/ 12 июля 2020

Я бы предложил изменить область действия метода private на package или protected. Затем вы можете переопределить его в тестовом классе, который расширяет ваш класс.

Я бы не пытался имитировать все службы, используемые в методе 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, потому что

  • единственная ответственность как за ClientClass, так и за EmailChecklistNotifier
  • он открыт-закрывается - вы можете заменить его макетом или другими реализациями, возможно, SMS-уведомление
  • отдельный интерфейс - ChecklistNotification
  • инвертировал зависимость и, следовательно, развязал ClientClass из зависимостей реализации отправки почты.
...