Feature Toggle JUnit
Feature Toggle,简单来说,就是一个开关,将未完成功能的代码屏蔽后发布到生产环境,从而避免多分支的情况。之所以有本文的产生,就是源于此情景。在引入Feature Toggle的同时,我们发现之前对这些未开发完功能的代码的单元测试不是很稳定,而且如果我们在用feature toggle关掉这个功能之后,这些测试也是对发布毫无价值可言,所有我们需要将这些测试全部屏蔽掉,以免影响运行其他测试结果。
在经过项目组讨论之后,我们毅然决然摒弃了直接采用@Ignore的低级做法,决定自己来实现一个简单的toggle,用annotation加读取配置文件的方式管理需要被屏蔽的测试。下面先介绍两种方式来实现这一toggle:
这两种方法都必须定义一个annotation和配置文件,定义如下:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface FeatureToggle {
public String feature();
}
1.先介绍一种简单的实现,也就是给测试实现一个runner, 封装一层判断条件,让他处理掉包含我们自己定义的annotation从而达到toggle的开关作用。
public class FeatureRunner extends BlockJUnit4ClassRunner {
@Override
protected void runChild(FrameworkMethod method, RunNotifier notifier) {
FeatureToggle annotationOnMethod = method.getAnnotation(FeatureToggle.class);
FeatureToggle annotationOnClass = method.getMethod().getDeclaringClass().getAnnotation(FeatureToggle.class); if (annotationOnClass != null) {
annotationOnMethod = annotationOnClass;
} String featureToggle = getToggleValue(annotationOnMethod); //从配置文件中读取annotationOnMethod.feature() 在properties文件中对应的value if (annotationOnMethod != null && "off".equals(featureToggle)) {
notifier.fireTestIgnored(describeChild(method));
} else {
super.runChild(method, notifier);
}
}
}
接下来在测试代码中使用方法如下:
@RunWith(FeatureRunner.class)
public class FeatureRunnerTest { @Test
@FeatureToggle(feature = "feature")
public void testTurnOn() throws Exception {
fail();
}
}
配置文件只需设置 feature=off 即可关掉所有同一个功能的所有加有annotation的测试。
2.采用@Rule的方式。JUnit 4.7 已经发布了,该版本具有一个重要的新特性:Rule。来一段最新junit框架里BlockJUnit4ClassRunner类中的代码来
protected Statement methodBlock(FrameworkMethod method) {
Object test;
try {
test= new ReflectiveCallable() {
@Override
protected Object runReflectiveCall() throws Throwable {
return createTest();
}
}.run();
} catch (Throwable e) {
return new Fail(e);
}
Statement statement= methodInvoker(method, test);
statement= possiblyExpectingExceptions(method, test, statement);
statement= withPotentialTimeout(method, test, statement);
statement= withBefores(method, test, statement);
statement= withAfters(method, test, statement);
statement= withRules(method, test, statement);
return statement;
}
这段代码实际上可以看出在执行@Before和@After操作的同时,还会调用@Rule的,对于具体的实现大家可以去这个类里面深究,我就直接告诉大家,@Rule会在before之前执行。
下面是如何自己写一个类来实现TestRule从来控制测试是否执行:
public class FeatureToggleRule implements TestRule {
@Override
public Statement apply(Statement base, Description description) {
FeatureToggle annotationOnClass = description.getTestClass().getAnnotation(FeatureToggle.class);
FeatureToggle annotationOnMethod = description.getAnnotation(FeatureToggle.class);
if (annotationOnClass != null) {
annotationOnMethod = annotationOnClass;
} if (annotationOnMethod != null && isToggleOFF(annotationOnMethod)) { //读取配置文件
return new IgnoreStatement();
}
return base;
} class IgnoreStatement extends Statement {
@Override
public void evaluate() throws Throwable {
throw new AssumptionViolatedException("ignore by rule");
}
}
}
这里如果方法名或者函数名上又跟第一种实现同样的annotation和配置文件,加上如下声明:
public class FeatureToggleRuleTest {
@Rule
public TestRule rule = new FeatureToggleRule(); @Test
@FeatureToggle(feature = "feature")
public void testTurnOn() throws Exception {
fail();
}
}
Rule更具有灵活性,并且功能不仅仅如此,我们可以在给自己的测试添加很多rule规则,这里不进行深究。
总结:两种方式,都实现同一个思想,用注解加配置文件来控制所有未完成功能测试部分的开关控制,而且简单易行,并且可以为大家拓展更多的junit需求提供指导参考,谢谢。
Feature Toggle JUnit的更多相关文章
- 基于Feature Flag的下一代开发模式
渐进式发布(Progressive Delivery)被认为是持续发布(Continous Delivery)的下一代形态,其专注于增强发布过程控制与降低发布风险,最终提高整体收益.国际科技巨头比如A ...
- spotify engineering culture part 1
原文 ,因为原视频说的太快太长, 又没有字幕,于是借助youtube,把原文听&打出来了. 中文版日后有时间再翻译. one of the big succeess factors here ...
- go语言项目汇总
Horst Rutter edited this page 7 days ago · 529 revisions Indexes and search engines These sites prov ...
- 近期关于CI/CD策略以及git分支模型的思考
近两个月由于个人处于新环境.新项目的适应阶段,没怎么提笔写些文章.中间有好几个想法想记录下来分享,但受限于没有很好的时间段供自己总结思考(也可以总结为间歇性懒癌和剧癌发作),便啥也没有更新.借这个周末 ...
- Golang优秀开源项目汇总, 10大流行Go语言开源项目, golang 开源项目全集(golang/go/wiki/Projects), GitHub上优秀的Go开源项目
Golang优秀开源项目汇总(持续更新...)我把这个汇总放在github上了, 后面更新也会在github上更新. https://github.com/hackstoic/golang-open- ...
- 版本分支管理标准 - Trunk Based Development 主干开发模型
之前分享过<版本分支管理标准 - Git Flow>,不过在实际使用过程中, 因为其有一定的复杂度,使用起来较为繁琐,所以一些人员较少的团队并不会使用这个方案. 在这基础上,一些新的分支管 ...
- 解决fastjson反序列化日期0000-00-00失败的方案
解决fastjson反序列化日期0000-00-00失败的方案 22 Jul 2016 一.案例场景复原 示例场景里涉及两个class:TestDemo.java, DateBeanDemo.java ...
- Cucumber(3)——命令以及日志
目录 回顾 基本执行命令 关于日志的生成 回顾 在上一节中,我介绍了cucumber一些基本的语法内容,如果你还没有进行相关的了解或者环境的配置,你可以点击这里来进行了解一下 在本节中,我会对cucu ...
- git原理及如何选择分支模式
一.git 原理介绍 1.git的四个工作区域 Git有四个工作区域:工作目录(Working Directory).暂存区(Stage/Index).资源库(Repository或Git Direc ...
随机推荐
- e621. Activating a Keystroke When Any Child Component Has Focus
Normally, a keystroke registered on a component is activated when the component has the focus. This ...
- 一、Open CV3.0.0 与 VS2012配置
原创:博乐Bar,转载请注明出处. 第一步,准备软件及开发环境 1.OpenCV 3.0.0 下载地址:http://www.opencv.org.cn/index.php/Download ,下载最 ...
- html dom基本操作
//div出滚动条: <div id="discussion" style="height:500px;overflow:auto;"></d ...
- PHP中如何获取网站根目录物理路径
在php程序开发中经常需要获取当前网站的目录,我们可以通过常量定义获取站点根目录物理路径,方便在程序中使用. 下面介绍几种常用的获取网站根目录的方法. php获取网站根目录方法一: <?php ...
- Java中关于“=”和“==”的分析
Java中变量分为普通原始变量(int char float等)和对象 一"=" (1)普通原始变量 普通原始变量的声明和赋值语句例如以下 int a=3; int b=a; 此时 ...
- R基本介绍
一.基本介绍:1. 警告:在输入命令前请切换到英文模式.否则你的一大段代码可能因为一个中文状态的括号而报错,R语言的报错并不智能无法指出错误的具体位置.最可怕的是不报错但就是无法输出正确结果.2. 警 ...
- javaScript实现归并排序
归并排序是一个O(nlogn)的算法,其基本思想就是一个分治的策略,先进行划分,然后再进行合并,下面举个例子.有这样一组数据: {5,4,1,22,12,32,45,21} 如果对它进行归并排序的话, ...
- ubis文件系统的制作
在linux-2.6.27以前,谈到Flash文件系统,大家很多时候多会想到cramfs.jffs2.yaffs2等文件系统.它们也都是基于文件系统+mtd+flash设备的架构.linux-2.6. ...
- 使用 MVVMLight 命令绑定
首先,如果您希望了解更多的MVVMLight技术或希望有顺序的学习MVVMLight,请查阅目录<MVVMLight 设计模式系列使用文章>. 继上一篇文章的项目,我们实现了数据绑定到界面 ...
- jquery 中的回调函数,回调函数(callback)是什么?
知乎上果然大牛比较多 大神解释如下: 你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货.在这个例子里, ...