相信很多道友搞开发的一般都会用到Junit单元测试工具,不知道大家有没有遇到一个这样的问题:
有的单元测试用例有很多@Test方法,甚至有的方法会执行很长时间,只能空等执行。而实际上我们只需要运行其中的某一些方法就可以了。然后有人会说不是有ingore注解么,可ingore需要为许多的方法添加,当测试方法达到一定数量级的时候,改起来会很烦躁,如果commit到代码服务器上甚至可能会影响别人工作。己所不欲...
之前有朋友跟我说过TestNG是支持指定执行哪些方法,本人没有亲自去实验,因为公司统一使用Junit,所以没打算在这上面花费学习成本,没有固定测试框架的朋友不妨自己了解一下。下面开始扩展:
实现思路
1、在正常运行的情况下,Junit被触发会调用org.junit.runners.BlockJUnit4ClassRunner类,加载测试类文件,执行before after childrenInvoker等方法,有兴趣的道友可以自己看下这个类的结构,今天的主角是childrenInvoker方法,这个方法调用了测试类文件的@Test方法并执行,我们要做的就是重写这个方法,根据我们自己的规则选择执行哪些方法。
2、根据上一条我们要扩展一个R我unner继承自BlockJUnit4ClassRunner,在这里进行参数过滤。
3、我们可能希望方法可以模糊匹配,也可能希望可以指定某几个固定的写法,所以需要引入一种过滤规则,这里采用正则表达式。过滤规则的传递采用注解,因为我觉得简洁,忘记注解使用的朋友可以点击这里。
4、Junit4开始提供了RunWith注解,以便让用户自定义扩展Runner,我们的实现就是基于它的这个特性。比较有名的应该大家都比较熟悉spring的Junit扩展。
代码实现:
1、定义注解
package com.array7.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface FilterMethods { String[] methods(); }
2、定义Runner
package com.array7.runner; import java.util.HashSet; import java.util.Set; import java.util.regex.Pattern; import org.junit.runner.notification.RunNotifier; import org.junit.runners.BlockJUnit4ClassRunner; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.InitializationError; import org.junit.runners.model.Statement; import com.array7.annotations.FilterMethods; public class SpecialMethodsRunner extends BlockJUnit4ClassRunner { private FilterMethods filter; public SpecialMethodsRunner(Class<?> clazz) throws InitializationError { super(clazz); filter = clazz.getAnnotation(FilterMethods.class); } /** * EnterPoint */ @Override protected Statement childrenInvoker(final RunNotifier notifier) { if (filter == null) { // keep original runner alone. return super.childrenInvoker(notifier); } return new Statement() { @Override public void evaluate() throws Throwable { runMethodsWithFilter(notifier, filter); } }; } /** * Filter the methods could be run. * @param notifier * @param filterMethods */ private void runMethodsWithFilter(final RunNotifier notifier, final FilterMethods filterMethods) { String[] filters = filterMethods.methods(); if (filters == null || filters.length == 0) { throw new IllegalArgumentException( "Wrong parameters!Please check Annotation FilterMthods parameters..."); } Set<Pattern> patternSet = new HashSet<Pattern>(); for (String filter : filters) { patternSet.add(Pattern.compile(filter)); } for (FrameworkMethod method : getChildren()) { for (Pattern pattern : patternSet) { // loop all patterns if (pattern.matcher(method.getName()).matches()) { // if matches ...break; runChild(method, notifier); break; } } } } }
3、使用实例:
package junit_ext; import org.junit.Test; import org.junit.runner.RunWith; import com.array7.annotations.FilterMethods; import com.array7.runner.SpecialMethodsRunner; @RunWith(SpecialMethodsRunner.class) @FilterMethods(methods = { "^.*2$", "^m.*", "ab21"}) public class DemoTest { @Test public void m1() { System.out.println(123); } @Test public void mmm2() { System.out.println(456); } @Test public void a2() { System.out.println(791); } @Test public void ab21() { System.out.println(7890); } }
4、pom.xml依赖
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency>
5、代码经过测试,文章亦可随意转载,唯请保留出处。
最后,喜欢讨论技术的道友可以加入我的QQ技术群80466913,Java相关为主,希望您喜欢技术,希望您对底层源码有一定了解(NIO / CONCURRENT / NETTY / 设计模式 / NOSQL / HADOOP / TCP/IP等),期待共同进步,此群上限只会维持到100人左右。