成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

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

李世贊 / 3524人閱讀

摘要:前言在建立的過程中,往往需要對當(dāng)前的測試樣例和注解進(jìn)行驗(yàn)證,比如檢查測試類是否含有非靜態(tài)內(nèi)部類,測試類是否是的。的驗(yàn)證機(jī)制非常精致而優(yōu)美,在本次博客中我們就主要來談一談機(jī)制的實(shí)現(xiàn)。首先在中定義三個默認(rèn)的類,如下。

前言

在建立Runner的過程中,往往需要對當(dāng)前的測試樣例和注解進(jìn)行驗(yàn)證,比如檢查測試類是否含有非靜態(tài)內(nèi)部類,測試類是否是Public的。Junit的驗(yàn)證機(jī)制非常精致而優(yōu)美,在本次博客中我們就主要來談一談Validator機(jī)制的實(shí)現(xiàn)。

指定一個驗(yàn)證器

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

@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注解會指定相關(guān)的用戶自定義Validator。AnnotationValidator是真正執(zhí)行驗(yàn)證操作的單元,至于這些Validator的Validate方法在何時調(diào)用,我們會在文章的最后一部分講解。

對一個類進(jìn)行驗(yàn)證

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

首先在AnnotationsValidator中定義三個默認(rèn)的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);
        }
    }

然后依次調(diào)用這三種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,而且在真正驗(yàn)證的時候調(diào)用的是它們的validateTestClass方法。它們其實(shí)也并非驗(yàn)證的真正執(zhí)行單元,它們首先找到相應(yīng)TestClass的所有對應(yīng)層面的注解,然后看這些注解是否是ValidateWith類型,是的話則由類的內(nèi)置工廠來提供具體的AnnotationValidator。詳細(xì)情況我們在下一小節(jié)中描述。

擴(kuò)展與默認(rèn)的結(jié)合——漂亮的工廠

首先我們給出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存儲注解和對應(yīng)的實(shí)際AnnotationValidator實(shí)例,而AnnotableValidator內(nèi)置通過內(nèi)置一個工廠來存儲所有對應(yīng)層級的驗(yàn)證器實(shí)例,并調(diào)用這些驗(yàn)證器對應(yīng)層級的驗(yàn)證方法來返回可能的異常,我們下面貼出該內(nèi)部類的代碼:

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;
        }
    }

可以說這個帶工廠的內(nèi)部類是一處神來之筆,整個流程是AnnotationsValidator類的validateTestClass方法依次調(diào)用職責(zé)鏈中三個層級的AnnotatableValidator,它們先找出所有對應(yīng)層次上的注解,再濾掉那些不是ValidateWith類型的注解,然后通過一個工廠來維護(hù)所有驗(yàn)證器實(shí)例,調(diào)用這些實(shí)例來真正驗(yàn)證。因?yàn)閷τ诓煌腡estClass,我們在一個層面上只用維護(hù)一個工廠。使用內(nèi)部類,只暴露應(yīng)該暴露的,擴(kuò)展的用戶只應(yīng)擴(kuò)展自定義的Validator,不應(yīng)該在層次邏輯上進(jìn)行擴(kuò)展,不應(yīng)該在整體驗(yàn)證的AnnotationsValidator之外再使用任何多帶帶層次的AnnotatableValidator。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/65451.html

相關(guān)文章

  • Junit源碼閱讀(一)

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

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

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

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

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

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

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

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

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

    vpants 評論0 收藏0

發(fā)表評論

0條評論

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