• 【JUnit4.10源码分析】6.1 排序和过滤


     abstract class ParentRunner<T> extends Runner implements Filterable,Sortable

    本节介绍排序和过滤。

    (尽管JUnit4.8.2源码分析-6.1 排序和过滤中演示了客户使用排序和过滤的方式,也有些不明确其设计意图。可是。先读懂源码为妙。说不定看着看着就明确了。

    org.junit.runner.manipulation包

    排序和过滤的相关类型。在org.junit.runner.manipulation包中。Sortable和Filterable是两个依赖注入接口。而Sorter和Filter的apply是注入方法

    1.比如Sortable是一个函数接口。yqj2065认为Sortable.sort(Sorter)不如叫Sortable.setSorter(Sorter)

    package org.junit.runner.manipulation;
    public interface Sortable {
    	public void sort(Sorter sorter);
    }
    2.Filterable类似,定义了void filter(Filter filter) throws NoTestsRemainException;

    3.NoTestsRemainException抱怨filter 将全部的測试都过滤掉了。


    4.Sorter implements Comparator<Description>。我们知道。java.util.Comparator接口是一个策略类,定义了int compare(T o1, T o2)方法。而Sorter是一个简单的代理模式的Proxy角色。

    通过构造器注入的方式Sorter(Comparator<Description>comparator)初始化realSubject角色。測试程序猿能够定义自己的排序器。并且。Sorter应用Null Object模式,定义了NULL静态内部子类。

    package org.junit.runner.manipulation;
    import java.util.Comparator;
    import org.junit.runner.Description;
    public class Sorter implements Comparator<Description> {
    	/**
    	 * NULL is a <code>Sorter</code> that leaves elements in an undefined order
    	 */
    	public static Sorter NULL= new Sorter(new Comparator<Description>() {
    		public int compare(Description o1, Description o2) {
    			return 0;
    		}});
    
    	public void apply(Object object) {
    		if (object instanceof Sortable) {
    			Sortable sortable = (Sortable) object;
    			sortable.sort(this);
    		}
    	}
    
    	
    }
    
    Sorter的方法apply(Object object),将this应用于Object 身上。

    5.Filter是一个抽象类。当须要过滤某些測试时。測试程序猿要定义自己的过滤器。

    Filter应用Null Object模式,定义了ALL静态内部子类。静态工厂生成public static Filter matchMethodDescription(final Description desiredDescription)。而public Filter intersect(final Filter second)同意多个Filter串接。

    依照上述几个样例,我们能够写出自己的过滤器。

    package sortFilter;
    import java.util.Arrays;
    import java.util.HashSet;
    import java.util.Set;
    import org.junit.runner.Description;
    import org.junit.runner.manipulation.Filter;
    
    /**
     *排除指定的方法。
     * @author yqj2065
     */
    public class MethodNameFilter extends Filter {
        private final Set<String> excludedMethods = new HashSet<>();
    
        public MethodNameFilter(String... excludedMethods) {
            this.excludedMethods.addAll(Arrays.asList(excludedMethods));
        }
    
        @Override
        public boolean shouldRun(Description description) {
            String methodName = description.getMethodName();
            return !excludedMethods.contains(methodName);
        }
    
        @Override
        public String describe() {
            return this.getClass().getSimpleName() + "-excluded methods: "
                    + excludedMethods;
        }
    }
    Unit4有測试方法a() 、@Ignore b() 、c() 和d()等,

    package demo;
    
    import static tool.Print.*;
    import org.junit.runner.manipulation.NoTestsRemainException;
    import org.junit.runner.notification.RunNotifier;
    import org.junit.runners.BlockJUnit4ClassRunner;
    import org.junit.runners.model.InitializationError;
    import sortFilter.MethodNameFilter;
    import units.Unit4;
    
    /**
     *
     * @author yqj2065
     */
    public class FilterDemo {
    
        public static void main(String... args) {
            try {
                BlockJUnit4ClassRunner runner = null;
                try {
                    runner = new BlockJUnit4ClassRunner(Unit4.class);
                } catch (InitializationError e) {
                }
                runner.filter(new MethodNameFilter("a","b","c", "d"));//排除全部
                runner.run(new RunNotifier());
            } catch (NoTestsRemainException ex) {
                pln(ex);
            }
        }
    }
    输出:org.junit.runner.manipulation.NoTestsRemainException

    保留@Ignore b(),尽管没有运行測试。可是不抛出异常。

    ParentRunner<T>与排序和过滤

    ParentRunner implements Filterable,Sortable 

    注意到:JUnit4.8.2中ParentRunner 有域Filter fFilter= null;而JUnit4.10不再有该域。而是以过滤后的private List<T> fFilteredChildren= null代替。

    因为ParentRunner<T>的类型參数T,代表其某种孩子的类型。BlockJUnit4ClassRunner的T为FrameworkMethod。Suite的T为Runner

    在ParentRunner中统一地处理T显得比較复杂。并且JUnit4.10代码变化较大。

    过滤相关的代码

    getFilteredChildren()惰性初始化域fFilteredChildren,当中调用getChildren()由子类给出实现,返回List<T>。

    @Override filter(Filter filter),就须要差别对待FrameworkMethod和Runner

    1.JUnit没有使用instanceof。而是利用abstract Description describeChild(T child),无论T是FrameworkMethod还是Runner。总能够构造(FrameworkMethod)或获得(Runner)一个Description返回值;

    2.而Filter定义的public abstract boolean shouldRun(Description description),能够统一处理两者。

    3.因而。ParentRunner定义了boolean shouldRun(Filter filter, T each) ,调用前者。


    可是,从实际參数看,filter.shouldRun(FrameworkMethod的Description )才进行比較和过滤;而filter.shouldRun(Runner.getDescription ),总是返回true、

    于是,第5行代码if (shouldRun(filter, each))出现有意思的情况。

    对于FrameworkMethod each。假设shouldRun,其代码应该为

    try {
    //
    } catch (NoTestsRemainException e) {
    iter.remove();
    }

    由于filter.apply(FrameworkMethod )肯定直接return;而shouldRun推断不通过,就意味着iter.remove();在fFilteredChildren中删除该方法;

    对于Runner each。总是shouldRun,并且运行filter.apply(each);从而调用到each.filter(filter);能够看出。假设没有FrameworkMethod ,能够直接运行each.filter(filter);可是如今不得不打乒乓球。利用filter.apply(each)排除掉FrameworkMethod 。

        private List<T> fFilteredChildren= null;
        public void filter(Filter filter) throws NoTestsRemainException {
            for (Iterator<T> iter = getFilteredChildren().iterator(); iter.hasNext(); ) {
                T each = iter.next();
                if (shouldRun(filter, each))
                    try {
                        filter.apply(each);
                    } catch (NoTestsRemainException e) {
                        iter.remove();
                }
                else
                    iter.remove();
            }
            if (getFilteredChildren().isEmpty()) {
                throw new NoTestsRemainException();
            }
        }
        private List<T> getFilteredChildren() {
            if (fFilteredChildren == null)
                fFilteredChildren = new ArrayList<T>(getChildren());
            return fFilteredChildren;
        }
        private boolean shouldRun(Filter filter, T each) {
            return filter.shouldRun(describeChild(each));
        }
        

    作为比較,JUnit4.8.2的相关代码列在以下,有时间再看。

        private Filter fFilter= null;
        public void filter(Filter filter) throws NoTestsRemainException {
            fFilter= filter;
            for (T each : getChildren())
                if (shouldRun(each))
                    return;
            throw new NoTestsRemainException();
        }
    
        private List<T> getFilteredChildren() {
            ArrayList<T> filtered= new ArrayList<T>();
            for (T each : getChildren())
                if (shouldRun(each))
                    try {
                        filterChild(each);
                        sortChild(each);
                        filtered.add(each);
                    } catch (NoTestsRemainException e) {
                        // don't add it
            }
            Collections.sort(filtered, comparator());
            return filtered;
        }
    
    
        private void filterChild(T child) throws NoTestsRemainException {
            if (fFilter != null)
                fFilter.apply(child);
        }
    
        private boolean shouldRun(T each) {
            return fFilter == null || fFilter.shouldRun(describeChild(each));
        }

    排序的非常easy。略。


  • 相关阅读:
    oracle rank() 排名函数
    oracle rank over partition by
    oracle over函数
    oracle extract函数
    mybatis的<choose>和<when>、<otherwise>标签
    python字符串操作实方法大合集
    GO安全并发之无锁原子操作
    设计模式(Design Patterns)Java版
    Linux内核参数调优
    TCP协议解析
  • 原文地址:https://www.cnblogs.com/cynchanpin/p/6774132.html
Copyright © 2020-2023  润新知