Как написать junit, чтобы проверить, перехвачено ли исключение, сгенерированное методом? - PullRequest
0 голосов
/ 23 ноября 2018

У меня есть фрагмент кода в моем приложении для весенней загрузки, который проверяет адреса электронной почты

class EmailValidation {

    public static void validate(List<String> s){
        try {
            for (String address : s) {
                if (s == null || s.indexOf("@") < 0) {  
                    throw new InvalidEmailAddressException("Email address is invalid ");
                }
                new InternetAddress(s);
            }
        } catch(AddressException e){
            LOGGER.Error("Please validate email addresses");
        }
        catch(InvalidEmailAddressesException e){
            LOGGER.error(e.getMessage());
        }
    }

    class InvalidEmailAddressException extends Exception {

        public InvalidEmailAddressException(String message) {
            super(message)
        }
    }
}

Я хочу написать тест Junit, который проверит, что InvalidEmailAddressesException было выброшено и CAUGHT.Как я могу сделать это в JUnit?

Ответы [ 3 ]

0 голосов
/ 24 ноября 2018

Действительно, использование java Exception для общей причины считается плохой практикой, и, как сказал @Michael, исключения должны быть исключительными , потому что

  • они нарушают управление потоком
  • они медленные (подробности здесь Насколько медленны исключения Java? )
  • они не смешиваются с функциональной парадигмой (где Java частично собирается с добавлением lamda-выражения

Однако создание пользовательского объекта для переноса данных проверки - это хорошо, и InvalidEmailAddressException можно превратить в CheckedEmail:

import java.util.List;
import java.util.stream.Collectors;

public class EmailValidator {

    public List<CheckedEmail> validate(List<String> emailAddresses) {
        return emailAddresses.stream().map(this::validate).collect(Collectors.toList());
    }

    public CheckedEmail validate(String emailAddress) {
        String[] emailParts = emailAddress.toString().split( "@", 3 );
        final boolean valid;
        if ( emailParts.length != 2 ) {
            valid = false;
        } else {
            // More validation can go here using one or more regex
            valid = true;
        }
        return new CheckedEmail(emailAddress, valid);
    }

    public static final class CheckedEmail {
        private final String emailAddress;
        private final boolean valid;

        private CheckedEmail(String emailAddress, boolean valid) {
            this.emailAddress = emailAddress;
            this.valid = valid;
        }

        public String getEmailAddress() {
            return emailAddress;
        }

        public boolean isValid() {
            return valid;
        }
    }
}

Это, в свою очередь, может бытьпроверено довольно легко (и улучшено с помощью параметризованного теста):

import static org.assertj.core.api.Assertions.assertThat;

import java.util.Arrays;
import java.util.List;

import org.junit.Test;

public class EmailValidatorTest {

    private final EmailValidator emailValidator = new EmailValidator();

    @Test
    public void invalid_email() {
        EmailValidator.CheckedEmail checkedEmail = emailValidator.validate("missing.an.at.symbol");

        assertThat(checkedEmail.isValid()).isFalse();
    }

    @Test
    public void valid_email() {
        EmailValidator.CheckedEmail checkedEmail = emailValidator.validate("at.symbol@present");

        assertThat(checkedEmail.isValid()).isTrue();
    }

    @Test
    public void multiple_email_addresses() {
        List<String> emailAddresses = Arrays.asList("missing.an.at.symbol", "at.symbol@present");

        List<EmailValidator.CheckedEmail> checkedEmails = emailValidator.validate(emailAddresses);

        assertThat(checkedEmails)
                .extracting(ce -> ce.getEmailAddress() + " " + ce.isValid())
                .containsExactly(
                        "missing.an.at.symbol false",
                        "at.symbol@present true");
    }
}

Если где-то нужно просто записать это, то:

List<EmailValidator.CheckedEmail> checkedEmails = emailValidator.validate(emailAddresses);

checkedEmails.stream()
        .filter(ce -> !ce.isValid())
        .map(ce -> String.format("Email address [%s] is invalid", ce.getEmailAddress()))
        .forEach(logger::error);

Надеюсь, это поможет!

0 голосов
/ 24 ноября 2018

Не подходите к тестированию таким образом.Вы должны тестировать только указанное поведение вашего кода, а не детали его реализации.

Если тестируемый метод делегирует метод, который вызывает исключение checked , и метод, который вы тестируететакже не объявляет, что throws, который проверял исключение, компилятор принудительно заставит метод перехватить исключение.Таким образом, в этом случае модульный тест не требуется.

Если тестируемый вами метод делегирует метод, который вызывает исключение unchecked , обратитесь к спецификации метода, чтобы определить, допустимо ли для тестируемого метода также генерировать (распространять (распространять)) это исключение.Если для него неприемлемо распространение исключения, вам следует создать тестовый пример, который заставит делегированный метод генерировать это непроверенное исключение.Если метод распространяет исключение, контрольный пример не пройден.Как это сделать?Это зависит от метода, которому делегированы, но в большинстве случаев вам нужно будет использовать Dependency Injection для предоставления фиктивного объекта, который выдает исключение.

0 голосов
/ 23 ноября 2018

В целом я согласен с комментариями о том, что такой тест, вероятно, не нужен.

Однако, если бы я хотел протестировать что-то подобное, я бы протестировал два случая по отдельности, и это потребует небольшой модификации вашего кода..

Во-первых, я бы создал метод, который генерирует исключение, только если оно есть.

public static void checkAddresses(List<String> s) throws AddressException, InvalidEmailAddressException {
    for (String address : s) {
         if (s == null || s.indexOf("@") < 0) {  
             throw new InvalidEmailAddressException("Email address is invalid ");
         }
         new InternetAddress(s);
    }
}

, тогда я бы использовал его в вашем коде так:

class EmailValidation {

    public static void validate(List<String> s){
         try {
             checkAddresses(s); // a wrapper method that throws the expected exceptions
         } catch(AddressException e){
             LOGGER.Error("Please validate email addresses");
         }
         catch(InvalidEmailAddressesException e){
             LOGGER.error(e.getMessage());
         }
     }

     // add checkAddresses here or somewhere appropriately

     class InvalidEmailAddressException extends Exception {

         public InvalidEmailAddressException(String message) {
             super(message)
         }
     }

}

Затем я написал бы отдельные тесты для checkAddresses, которые проверяют как наличие ожидаемого исключения 1015 * или нет, так и отдельные тесты для validate (возможно, с одним и тем же вводомэто было дано checkAddresses), которое должно пройти, если не сгенерировано исключение.

Кроме того, если вы хотите проверить свои журналы, вы можете попробовать что-то вроде , что .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...