簡體   English   中英

如何編寫一個junit來驗證是否捕獲了該方法引發的異常?

[英]How to write a junit to verify if an exception thrown by the method is caught?

我的春季啟動應用程序中包含以下代碼,該代碼可驗證電子郵件地址

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中做到這一點?

總的來說,我同意這樣的評論,即這種測試可能是不必要的。

但是,如果我想測試類似的東西,我將分別測試這兩種情況,這需要對您的代碼進行少量修改。

首先,我將構造一個僅在存在異常時拋出異常的方法。

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編寫單獨的測試,以測試是否預期發生異常,以及為validate編寫單獨的測試(可能具有與checkAddresses相同的輸入),如果未引發異常,則該測試應通過。

另外,如果您想驗證你的日志可能是你可以嘗試像那個

實際上,將java Exception用於常見原因被認為是一種不好的做法,正如@Michael所說, Exceptions必須是例外 ,因為

  • 他們破壞了流量控制
  • 它們很慢(這里更多詳細信息,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);

希望這可以幫助 !

不要以這種方式進行測試。 您應該僅測試代碼的指定行為,而不是其實現詳細信息。

如果您正在測試的方法委托給引發已檢查異常的方法,並且您正在測試的方法未同時聲明其throws已檢查異常,則編譯器將強制該方法捕獲該異常。 因此,在這種情況下,不需要進行單元測試。

如果您正在測試的方法委托引發未檢查異常的方法,請查閱該方法的規范,以確定被測方法也拋出(傳播)該異常是否可以接受。 如果它不能傳播異常,則應創建一個測試用例,以使委托的方法引發該未經檢查的異常。 如果該方法傳播異常,則測試用例將失敗。 怎么做? 這取決於委托給的方法,但是在大多數情況下,您將需要使用“依賴注入”來提供引發異常的模擬對象。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM