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

資訊專欄INFORMATION COLUMN

Junit源碼閱讀(六)之Junit中的設(shè)計(jì)模式

jlanglang / 1356人閱讀

摘要:前言在這次的博客中我們將著重于的許多集成性功能來(lái)討論中的種種設(shè)計(jì)模式。裝飾器模式裝飾器模式是為了在原有功能上加入新功能,在中絕對(duì)屬于使用最頻繁架構(gòu)中最核心的模式,等都是通過(guò)裝飾器模式來(lái)完成擴(kuò)展的。

前言

在這次的博客中我們將著重于Junit的許多集成性功能來(lái)討論Junit中的種種設(shè)計(jì)模式。可以說(shuō)Junit的實(shí)現(xiàn)本身就是GOF設(shè)計(jì)原則的范例教本,下面就讓我們開(kāi)始吧。

裝飾器模式

裝飾器模式是為了在原有功能上加入新功能,在Junit中絕對(duì)屬于使用最頻繁架構(gòu)中最核心的模式,Runner、Filter、Rule等都是通過(guò)裝飾器模式來(lái)完成擴(kuò)展的。下就以Filter的實(shí)現(xiàn)機(jī)制來(lái)說(shuō)明。

首先從命令行中解析出來(lái)的FilterSpec生成各種Filter,如下:

    private Request applyFilterSpecs(Request request) {
        try {
            for (String filterSpec : filterSpecs) {
                Filter filter = FilterFactories.createFilterFromFilterSpec(
                        request, filterSpec);
                request = request.filterWith(filter);
            }
            return request;
        } catch (FilterNotCreatedException e) {
            return errorReport(e);
        }
    }

request的Filter方法將會(huì)返回一個(gè)新的Request,不過(guò)是Request的子類FilterRequest,它依然保留原有的request,只不過(guò)在返回Runner的時(shí)候,再采用Filter過(guò)濾,如下:

public final class FilterRequest extends Request {
    private final Request request;
   
    private final Filter fFilter;

    
    public FilterRequest(Request request, Filter filter) {
        this.request = request;
        this.fFilter = filter;
    }

    @Override
    public Runner getRunner() {
        try {
            Runner runner = request.getRunner();
            fFilter.apply(runner);
            return runner;
        } catch (NoTestsRemainException e) {
            return new ErrorReportingRunner(Filter.class, new Exception(String
                    .format("No tests found matching %s from %s", fFilter
                            .describe(), request.toString())));
        }
    }
}

Filter的apply方法會(huì)調(diào)用runner自身實(shí)現(xiàn)的filter方法并以自己作為參數(shù),以ParentRunner為例,我們給出filter方法的一般實(shí)現(xiàn)。

public void filter(Filter filter) throws NoTestsRemainException {
        synchronized (childrenLock) {
            List children = new ArrayList(getFilteredChildren());
            for (Iterator iter = children.iterator(); iter.hasNext(); ) {
                T each = iter.next();
                if (shouldRun(filter, each)) {
                    try {
                        filter.apply(each);
                    } catch (NoTestsRemainException e) {
                        iter.remove();
                    }
                } else {
                    iter.remove();
                }
            }
            filteredChildren = Collections.unmodifiableCollection(children);
            if (filteredChildren.isEmpty()) {
                throw new NoTestsRemainException();
            }
        }
    }

顯然非原子的Runner通過(guò)維護(hù)一個(gè)filteredChildren列表來(lái)提供它所有通過(guò)過(guò)濾的child,每次有新的filter作用到之上,它都需要更新該列表。對(duì)于原子的測(cè)試,它會(huì)提供出它的description,由Filter實(shí)現(xiàn)的shouldRun方法來(lái)判斷是否會(huì)被過(guò)濾,這也是filteredChildren列表更新的原理。

當(dāng)我們先后有多個(gè)Filter時(shí),可以不停地包裝已有的FilterRequest,每個(gè)FilterRequest在getRunnere時(shí)都會(huì)先調(diào)用其內(nèi)部的Request,然后執(zhí)行相同的附加操作,也即更新內(nèi)部Request返回的Runner的filteredChildren列表。使用實(shí)現(xiàn)同一接口繼承同一父類的各個(gè)過(guò)濾器相互嵌套就可以實(shí)現(xiàn)一個(gè)過(guò)濾鏈。

工廠模式

工廠模式也在Junit中被大量使用,主要用來(lái)生產(chǎn)各類Rule、Filter等。我們依然以Filter機(jī)制為例來(lái)介紹一次抽象工廠的使用。FilterFactory是一個(gè)工廠接口如下:

public interface FilterFactory {
    
    Filter createFilter(FilterFactoryParams params) throws FilterNotCreatedException;

    
    @SuppressWarnings("serial")
    class FilterNotCreatedException extends Exception {
        public FilterNotCreatedException(Exception exception) {
            super(exception.getMessage(), exception);
        }
    }
}

FilterFactories提供了各種由參數(shù)來(lái)生成不同工廠的方法,同時(shí)又使用生成的工廠來(lái)生成Filter,可以說(shuō)在廣義上這就是一個(gè)抽血工廠模式,不過(guò)FilterFactories完成了生產(chǎn)產(chǎn)品的過(guò)程,又集成了提供各類工廠的方法。下面給出代碼大家感受一下:

class FilterFactories {
    
    public static Filter createFilterFromFilterSpec(Request request, String filterSpec)
            throws FilterFactory.FilterNotCreatedException {
        Description topLevelDescription = request.getRunner().getDescription();
        String[] tuple;

        if (filterSpec.contains("=")) {
            tuple = filterSpec.split("=", 2);
        } else {
            tuple = new String[]{ filterSpec, "" };
        }

        return createFilter(tuple[0], new FilterFactoryParams(topLevelDescription, tuple[1]));
    }

    
    public static Filter createFilter(String filterFactoryFqcn, FilterFactoryParams params)
            throws FilterFactory.FilterNotCreatedException {
        FilterFactory filterFactory = createFilterFactory(filterFactoryFqcn);

        return filterFactory.createFilter(params);
    }

    
    public static Filter createFilter(Class filterFactoryClass, FilterFactoryParams params)
            throws FilterFactory.FilterNotCreatedException {
        FilterFactory filterFactory = createFilterFactory(filterFactoryClass);

        return filterFactory.createFilter(params);
    }

    static FilterFactory createFilterFactory(String filterFactoryFqcn) throws FilterNotCreatedException {
        Class filterFactoryClass;

        try {
            filterFactoryClass = Classes.getClass(filterFactoryFqcn).asSubclass(FilterFactory.class);
        } catch (Exception e) {
            throw new FilterNotCreatedException(e);
        }

        return createFilterFactory(filterFactoryClass);
    }

    static FilterFactory createFilterFactory(Class filterFactoryClass)
            throws FilterNotCreatedException {
        try {
            return filterFactoryClass.getConstructor().newInstance();
        } catch (Exception e) {
            throw new FilterNotCreatedException(e);
        }
    }
}
組合模式

在Junit中組合模式主要用于管理Runner和Description的組合。由于測(cè)試的需求十分多樣,有時(shí)需要測(cè)試單個(gè)方法,有時(shí)需要測(cè)試單個(gè)類的所有方法,有時(shí)又需要測(cè)試多個(gè)類的組合方法,所以對(duì)于測(cè)試的表達(dá)必須是強(qiáng)大的。組合模式顯然符合這個(gè)要求,根部的runner會(huì)調(diào)動(dòng)子節(jié)點(diǎn)的run,向上只暴露出根節(jié)點(diǎn)的run方法。由于之前幾篇中對(duì)這一部分論述較多,此處就不再贅述了。

觀察者模式

最典型的就是Notifier和Listener,當(dāng)測(cè)試開(kāi)始、結(jié)束、出現(xiàn)錯(cuò)誤時(shí),Notifier將通知它管理的Listener執(zhí)行相應(yīng)的操作,但有趣之處就在于為了能夠處理在通知過(guò)程中出現(xiàn)的異常,Notifer使用了一個(gè)內(nèi)部類SafeNotifier,所有的對(duì)應(yīng)事件(測(cè)試開(kāi)始等)覆寫SafeNotifier里的notifyListener函數(shù),在其中寫調(diào)用Listener的具體哪一個(gè)函數(shù)。相關(guān)的詳細(xì)內(nèi)容請(qǐng)參考上一篇博客,下面給出RunNotifier的源碼(刪去部分內(nèi)容)。

public class RunNotifier {
    private final List listeners = new CopyOnWriteArrayList();
    private volatile boolean pleaseStop = false;

    public void addListener(RunListener listener) {
        if (listener == null) {
            throw new NullPointerException("Cannot add a null listener");
        }
        listeners.add(wrapIfNotThreadSafe(listener));
    }

    
    public void removeListener(RunListener listener) {
        if (listener == null) {
            throw new NullPointerException("Cannot remove a null listener");
        }
        listeners.remove(wrapIfNotThreadSafe(listener));
    }

    RunListener wrapIfNotThreadSafe(RunListener listener) {
        return listener.getClass().isAnnotationPresent(RunListener.ThreadSafe.class) ?
                listener : new SynchronizedRunListener(listener, this);
    }


    private abstract class SafeNotifier {
        private final List currentListeners;

        SafeNotifier() {
            this(listeners);
        }

        SafeNotifier(List currentListeners) {
            this.currentListeners = currentListeners;
        }

        void run() {
            int capacity = currentListeners.size();
            List safeListeners = new ArrayList(capacity);
            List failures = new ArrayList(capacity);
            for (RunListener listener : currentListeners) {
                try {
                    notifyListener(listener);
                    safeListeners.add(listener);
                } catch (Exception e) {
                    failures.add(new Failure(Description.TEST_MECHANISM, e));
                }
            }
            fireTestFailures(safeListeners, failures);
        }

        abstract protected void notifyListener(RunListener each) throws Exception;
    }

    
    

    public void fireTestRunFinished(final Result result) {
        new SafeNotifier() {
            @Override
            protected void notifyListener(RunListener each) throws Exception {
                each.testRunFinished(result);
            }
        }.run();
    }
    
    public void fireTestFinished(final Description description) {
        new SafeNotifier() {
            @Override
            protected void notifyListener(RunListener each) throws Exception {
                each.testFinished(description);
            }
        }.run();
    }

    
}
職責(zé)鏈模式

可以參考之前的第三篇博客,Junit的Validator機(jī)制需要在三個(gè)層次——類、方法和域上進(jìn)行驗(yàn)證,采用了職責(zé)鏈模式。

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

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

相關(guān)文章

  • Junit源碼閱讀(一)

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

    Gilbertat 評(píng)論0 收藏0
  • Junit源碼閱讀(三)精致的Validator

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

    李世贊 評(píng)論0 收藏0
  • Junit源碼閱讀(五)

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

    vpants 評(píng)論0 收藏0
  • java9系列()HTTP/2 Client (Incubator)

    摘要:鑒于它還處在,如果不是著急使用,建議還是使用的,它是遵循規(guī)范的,使用起來(lái)更加方便。貌似要在版本才支持。揭秘讓支持協(xié)議如何啟用命令支持 序 本文主要研究下JEP 110: HTTP/2 Client (Incubator) 基本實(shí)例 sync get /** * --add-modules jdk.incubator.httpclient * @throws ...

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

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

    Little_XM 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<