国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Junit源碼閱讀(三)之精致的Validator

李世贊 / 3514人閱讀

摘要:前言在建立的過程中,往往需要對當前的測試樣例和注解進行驗證,比如檢查測試類是否含有非靜態內部類,測試類是否是的。的驗證機制非常精致而優美,在本次博客中我們就主要來談一談機制的實現。首先在中定義三個默認的類,如下。

前言

在建立Runner的過程中,往往需要對當前的測試樣例和注解進行驗證,比如檢查測試類是否含有非靜態內部類,測試類是否是Public的。Junit的驗證機制非常精致而優美,在本次博客中我們就主要來談一談Validator機制的實現。

指定一個驗證器

首先我們可以使用注解來指定某一個用戶自定義Validator來進行驗證,下面給出AnnotationValidator的父類以及相應注解。

@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface ValidateWith {
   Class value();
}
public abstract class AnnotationValidator {

    private static final List NO_VALIDATION_ERRORS = emptyList();

    public List validateAnnotatedClass(TestClass testClass) {
        return NO_VALIDATION_ERRORS;
    }

    public List validateAnnotatedField(FrameworkField field) {
        return NO_VALIDATION_ERRORS;

    }

    public List validateAnnotatedMethod(FrameworkMethod method) {
        return NO_VALIDATION_ERRORS;
    }
}

以上可以很清楚地看出ValidateWith注解會指定相關的用戶自定義Validator。AnnotationValidator是真正執行驗證操作的單元,至于這些Validator的Validate方法在何時調用,我們會在文章的最后一部分講解。

對一個類進行驗證

從上面的代碼可以看出一個Validator需要實現三方面的驗證——對類的驗證、對方法的驗證、對域的驗證,Junit使用職責鏈模式來提供了三方面的驗證。

首先在AnnotationsValidator中定義三個默認的Validator類,如下。

  private static class ClassValidator extends AnnotatableValidator {
        @Override
        Iterable getAnnotatablesForTestClass(TestClass testClass) {
            return singletonList(testClass);
        }

        @Override
        List validateAnnotatable(
                AnnotationValidator validator, TestClass testClass) {
            return validator.validateAnnotatedClass(testClass);
        }
    }

    private static class MethodValidator extends
            AnnotatableValidator {
        @Override
        Iterable getAnnotatablesForTestClass(
                TestClass testClass) {
            return testClass.getAnnotatedMethods();
        }

        @Override
        List validateAnnotatable(
                AnnotationValidator validator, FrameworkMethod method) {
            return validator.validateAnnotatedMethod(method);
        }
    }

    private static class FieldValidator extends
            AnnotatableValidator {
        @Override
        Iterable getAnnotatablesForTestClass(TestClass testClass) {
            return testClass.getAnnotatedFields();
        }

        @Override
        List validateAnnotatable(
                AnnotationValidator validator, FrameworkField field) {
            return validator.validateAnnotatedField(field);
        }
    }

然后依次調用這三種Validator

private static final List> VALIDATORS = Arrays.>asList(
            new ClassValidator(), new MethodValidator(), new FieldValidator());

    /**
     * Validate all annotations of the specified test class that are be
     * annotated with {@link ValidateWith}.
     * 
     * @param testClass
     *            the {@link TestClass} that is validated.
     * @return the errors found by the validator.
     */
    public List validateTestClass(TestClass testClass) {
        List validationErrors= new ArrayList();
        for (AnnotatableValidator validator : VALIDATORS) {
            List additionalErrors= validator
                    .validateTestClass(testClass);
            validationErrors.addAll(additionalErrors);
        }
        return validationErrors;
    }

我們可以看到ClassValidator等都繼承自AnnotatableValidator,而且在真正驗證的時候調用的是它們的validateTestClass方法。它們其實也并非驗證的真正執行單元,它們首先找到相應TestClass的所有對應層面的注解,然后看這些注解是否是ValidateWith類型,是的話則由類的內置工廠來提供具體的AnnotationValidator。詳細情況我們在下一小節中描述。

擴展與默認的結合——漂亮的工廠

首先我們給出AnnotationValidatorFactory的定義

public class AnnotationValidatorFactory {
    private static final ConcurrentHashMap VALIDATORS_FOR_ANNOTATION_TYPES =
            new ConcurrentHashMap();

    public AnnotationValidator createAnnotationValidator(ValidateWith validateWithAnnotation) {
        AnnotationValidator validator = VALIDATORS_FOR_ANNOTATION_TYPES.get(validateWithAnnotation);
        if (validator != null) {
            return validator;
        }

        Class clazz = validateWithAnnotation.value();
        try {
            AnnotationValidator annotationValidator = clazz.newInstance();
            VALIDATORS_FOR_ANNOTATION_TYPES.putIfAbsent(validateWithAnnotation, annotationValidator);
            return VALIDATORS_FOR_ANNOTATION_TYPES.get(validateWithAnnotation);
        } catch (Exception e) {
            throw new RuntimeException("Exception received when creating AnnotationValidator class " + clazz.getName(), e);
        }
    }

}

工廠通過一個線程安全的Map存儲注解和對應的實際AnnotationValidator實例,而AnnotableValidator內置通過內置一個工廠來存儲所有對應層級的驗證器實例,并調用這些驗證器對應層級的驗證方法來返回可能的異常,我們下面貼出該內部類的代碼:

private static abstract class AnnotatableValidator {
        private static final AnnotationValidatorFactory ANNOTATION_VALIDATOR_FACTORY = new AnnotationValidatorFactory();

        abstract Iterable getAnnotatablesForTestClass(TestClass testClass);

        abstract List validateAnnotatable(
                AnnotationValidator validator, T annotatable);

        public List validateTestClass(TestClass testClass) {
            List validationErrors= new ArrayList();
            for (T annotatable : getAnnotatablesForTestClass(testClass)) {
                List additionalErrors= validateAnnotatable(annotatable);
                validationErrors.addAll(additionalErrors);
            }
            return validationErrors;
        }

        private List validateAnnotatable(T annotatable) {
            List validationErrors= new ArrayList();
            for (Annotation annotation : annotatable.getAnnotations()) {
                Class annotationType = annotation
                        .annotationType();
                ValidateWith validateWith = annotationType
                        .getAnnotation(ValidateWith.class);
                if (validateWith != null) {
                    AnnotationValidator annotationValidator = ANNOTATION_VALIDATOR_FACTORY
                            .createAnnotationValidator(validateWith);
                    List errors= validateAnnotatable(
                            annotationValidator, annotatable);
                    validationErrors.addAll(errors);
                }
            }
            return validationErrors;
        }
    }

可以說這個帶工廠的內部類是一處神來之筆,整個流程是AnnotationsValidator類的validateTestClass方法依次調用職責鏈中三個層級的AnnotatableValidator,它們先找出所有對應層次上的注解,再濾掉那些不是ValidateWith類型的注解,然后通過一個工廠來維護所有驗證器實例,調用這些實例來真正驗證。因為對于不同的TestClass,我們在一個層面上只用維護一個工廠。使用內部類,只暴露應該暴露的,擴展的用戶只應擴展自定義的Validator,不應該在層次邏輯上進行擴展,不應該在整體驗證的AnnotationsValidator之外再使用任何多帶帶層次的AnnotatableValidator。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/65451.html

相關文章

  • Junit源碼閱讀(一)

    摘要:是對測試樣例的建模,用來組合多個測試樣例,是中的核心內容。也是一個虛類,子類應該實現方法來決定對于是否運行。如下列代碼所示組合了和,為運行時異常和斷言錯誤屏蔽了不一致的方面,可以向上提供錯誤信息和樣例信息。 Junit的工程結構 showImg(/img/bVsEeS); 從上圖可以清楚的看出Junit大致分為幾個版塊,接下來一一簡略介紹這些版塊的作用。 runner:定義了Jun...

    Gilbertat 評論0 收藏0
  • Junit源碼閱讀(四)自定義擴展

    摘要:前言上次的博客中我們著重介紹了的機制,這次我們將聚焦到自定義擴展上來。在很多情形下我們需要在測試過程中加入一些自定義的動作,這些就需要對進行包裝,為此提供了以接口和為基礎的擴展機制。 前言 上次的博客中我們著重介紹了Junit的Validator機制,這次我們將聚焦到自定義擴展Rule上來。在很多情形下我們需要在測試過程中加入一些自定義的動作,這些就需要對statement進行包裝,...

    Little_XM 評論0 收藏0
  • Junit源碼閱讀(六)Junit設計模式

    摘要:前言在這次的博客中我們將著重于的許多集成性功能來討論中的種種設計模式。裝飾器模式裝飾器模式是為了在原有功能上加入新功能,在中絕對屬于使用最頻繁架構中最核心的模式,等都是通過裝飾器模式來完成擴展的。 前言 在這次的博客中我們將著重于Junit的許多集成性功能來討論Junit中的種種設計模式。可以說Junit的實現本身就是GOF設計原則的范例教本,下面就讓我們開始吧。 裝飾器模式 裝飾器...

    jlanglang 評論0 收藏0
  • @angular/forms 源碼解析 Validators

    摘要:校驗器運行完成后,會設置屬性,從而計算的屬性,假設校驗錯誤,則屬性值為。這樣就理解了校驗器的整個運行過程,也包括為何校驗錯誤時會自動添加描述控件狀態的。 我們知道,@angular/forms 包主要用來解決表單問題的,而表單問題非常重要的一個功能就是表單校驗功能。數據校驗非常重要,不僅僅前端在發請求給后端前需要校驗數據,后端對前端發來的數據也需要校驗其有效性和邏輯性,尤其在存入數據庫...

    JowayYoung 評論0 收藏0
  • Junit源碼閱讀(五)

    摘要:的作用是包裝從生成的邏輯,提供兩種方案生成和。最后從生成也異常簡單,也就是實現其方法返回該。 前言 盡管在第二次博客中我們講述了Runner的運行機制,但是許多其他特性比如Filter是如何與運行流程結合卻并不清楚。這次我們來回顧整理一下Junit的執行流程,給出各種特性生效的機理,并分析一些代碼中精妙的地方。 Junit的執行流程 JUnitCore的RunMain方法,使用jUn...

    vpants 評論0 收藏0

發表評論

0條評論

李世贊

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<