
在 Java 测试中使用 Mockito 有段时日了,以前只是想当然的认为 Mock 的对象属性值和方法返回值都是依据同样的规则。基本类型是 0, 0.0, 或 false, 对象类型都是 null, Mock 对象的默认返回值也应该是一样的。直到最近有一天,有一个返回
Optional<String>类型的方法,由于忘记对该方法打桩,意外的发现它返回的不是 null, 而Optional.empty(), 因此才意识到此处定有蹊跷。着实有必要用代码验证一下 Mockito 是怎么决定属性及方法的各种返回类型的默认值的。此次测试所用的 Mockito 版本是 mockito-core-2.12.0.
于是创建了下面一个类 MyClass 用于生成 Mock 对象,选取了一些典型的数据类型, 包括 int, Double, String, long[], Optional<String>, Collection<String>, Map<String, String>, 同时测试 Mock 对象默认的属性值与方法默认返回值。 Read More

Spring 相关代码分析
本文通过对 Spring 的源代码来理解它是如何扫描 Bean 与资源的,因为自己有一个类似的需求,想把一堆的配置文件丢到 resources 下某个目录中,在程序启动的时候能加载它们。因为文件名是不一定的,所以不能直接指定文件名来加载,通过对 Spring 扫描资源的理解后,可以在自己的代码中手工扫描那些配置文件,以后有任何新的配置文件只需要扔到相应的配置目录即可。
下面以一个最简单的 Spring Boot 项目为例,调试并观察源代码1@SpringBootApplication 2@ComponentScan(basePackages = "cc.unmi") 3public class DemoApplication { 4 public static void main(String[] args) { 5 SpringApplication.run(DemoApplication.class, args); 6 } 7}
还是直奔主题吧,不一步一步的去探寻到底是哪个实现类去扫描资源的,用 Google 找到的是ClassPathScanningCandidateComponentProvider, 因此直接在这个类的敏感位置上打上断点,比如它的构造函数 Read More
使用 Vim 官方网站的字典下载链接
下载字典:
下载页面:http://www.vim.org/scripts/script.php?script_id=195, 当前下载链接为 http://www.vim.org/scripts/download_script.php?src_id=6351
解压缩所需字典文件
tar xzvf ~/Downloads/engspchk.targ.gz CVIMSYN/engspchk.dict
使用 Vim 整理成字典文件
vim CVIMSYN/engspchk.dict
删除前面三行:
gg3dd
删除行首 GoodWord单词::%s/^GoodWord\t//g
整理成每个单词占一行:%s/\t/^M/g,^M的输入要用ctrl-v再按回车键,也可以用ctrl-v-m来输入^M.
删除最后一行:Gdd
排序::sort现在的 engspchk.dict 中文件每一行只有一个单词,并且按字母排好了序的 Read More
- 昨天刚刚侍弄完 Spring 下基于自定义注解拦截方法调用, 现在试下纯 AspectJ 的方式来打造,因为不是每一个项目都是 Spring。这次要推到 5 年前试验过用 javac 命令行编译的方式织入方面, 见 AspectJ 基于自定义的方法注解来拦截方法, 这次着重在用 aspectj-maven-plugin 插件的方法来织入 AspectJ 方面。
基本上代码还是昨天的,需求还是一样的:
被 @LogStartTime 注解的方法在进入该方法时记录当前时间在 ThreadLocal 中,并能根据 @LogStartTime 的属性值决定处理逻辑
因为 Java5+ 之后 AspectJ 可以写成 Java 类加注解的方式,*.aj 文件一般都没太大必要了,所以可以和 Spring AOP 共用一个 @Aspect 注解的方面代码MethodStartAspect。
我们将采用编译器织入,因此项目依赖只需要一个org.aspectj:aspectjrt:1.8.0, 它也不会引入别的组件。同样我们从 Main 方法和测试用例两方面来验证实现的效果,下面是整个测试项目的布局,以及依赖,除掉单元测试的其时就只需要一个 jar 包。 Read More
其实很多年前就做过如此的实验,一翻开自己的日志有关于 aspectj site:yanbin.blog, 可以找到 2008 年写的日志。真是流光容易把人抛,红了樱桃,绿了巴蕉。只是那时候 Spring 刚步入 2.0, 才翻开强大 AOP 的篇章,还记得彼时只要是直接使用 AspectJ 就要写 *.aj 文件。而如今 Spring 都到 5.0 了,也就是一年前才重拾起 Spring, 这期间 AspectJ 早就可以不用 *.aj 文件,只需普通 Java 文件,加上 @Aspect 和 @Pointcut 之类的注解就行。
本文内容与几年前写过的日志大体相差不大,再缀上一篇纯粹是个人笔记。这里不以 Spring 5.0 为例,仍然是最新的 4.3.11.RELEASE, 并且直接用 Spring, 而非选择 Spring Boot, 因为用了 Spring Boot 常常搞不清楚哪些是自动配置了的。原生的 Spring 可以使自己掌握一个 Spring AOP 的基本要素。
需求:@LogStartTime 注解的方法,在每次进入该方法时把当前时间写入 ThreadLocal 中去,被 @LogStartTime 注解的方法中随时可以获得进入方法的时间 Read More
上一篇 JUnit 5 快速上手(从 JUnit 4 到 JUnit 5) 介绍了如何在一个项目中同时使用 JUnit 4 和 JUnit 5。现在来开始了解 JUnit 5 的新特性. 我们现在的项目基本是用 Maven 来管理依赖,在 Maven 项目中如何引入 JUnit 5 可以参考官方例子 junit5-maven-consumer. 我们知道 JUnit 5 包括三个模块,不用 JUnit 4 的话只要 Platform 和 Jupiter, 而 Jupiter Maven 模块本身依赖于 JUnit Platform, 因此应用 JUnit 5 的项目 Maven 配置就是1<dependency> 2 <groupId>org.junit.jupiter</groupId> 3 <artifactId>junit-jupiter-engine</artifactId> 4 <version>5.0.0</version> 5 <scope>test</scope> 6</dependency>
这样在当前的 IntelliJ IDEA(2017.2.4) 可以执行 JUnit 5 的测试用例。但要让 Maven 找到 JUnit 5 的测试用例,还得在pom.xml中加上 Read More
在研究 JUnit 5 新特性的时候,学习到其中有一节 Test Instance Lifecycle, 才意识到对 JUnit 的理解一直存在一个误区,以为 JUnit 是以测试类为一个生命周期的,其实不然。不管是 JUnit 5 还是 JUnit 4 或更早的版本,JUnit 都是以测试方法为一个独立的生命周期。
只是到了 JUnit 5 提供了方法来把生命周期由方法改为测试类,对于单个测试类可以使用注解
@TestInstance(Lifecycle.PER_CLASS)来指定用一个测试实例来跑所有的测试方法,这就意味着测试类中的成员变量只被初始化一次。@TestInstance的 Lifecycle 默认是 PER_METHOD, JUnit 4 就是 PER_METHOD, 而且是不能改的。如果在 JUnit 5 中改变为 PER_CLASS, 恐怕反而会出许多乱子,每个测试方法本就该是完全独立的。比如在同一个类中多个测试方法使用了同一个实例变量的情况下,总会用一个
@After方法来复位该实例变量,现在才知道那是多余的。像下面的代码1public class CalculatorTest { 2 3 private int number = 100; 4 5 @Test 6 public void test1() { 7 System.out.println(number); 8 number = 200; 9 } 10 11 @Test 12 public void test2() { 13 System.out.println(number); 14 number = 300; 15 } 16}
一直在关注 JUnit 5 的演进,自两年前首个 ALPHA 版后,经历了 6 的 Milestone, 3 个 RC 终于在 2017/09/10 正式发布了。其实还从未对其深究过,今天算是正式开始体验。
不像以往的版本,JUnit 5 现在是三个模块的合体 JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
- JUnit Platform: 运行测试的基础平台。还定义了开发测试框架的 TestEngine API。并提供了命令行执行测试以及与 Gradle, Maven, JUnit4 Runner 的集成
- JUnit Jupiter: 包含了新的编程和扩展模型。它还提供了一个运行新型测试的 TestEngine 实现
- JUnit Vintage: 提供了一个让 JUnit Platform 运行 JUnit 3 和 JUnit 4 的 TestEngine 实现
以上三个模块分工还是很明确,因此
- 从现有的 JUnit 4 项目步入到 JUnit 5 至少两 JUnit Platform 和 JUnit Vintage 两个
- 建立全新项目可以只引入 JUnit Platform 和 JUnit Jupiter
- 混合型当然是三个全部引入
但是由于 jar 包之间本身存在某种依赖关系,所以实际上 pom.xml 可以比想像的更简单 Read More

用过 Spring 的 @EnableScheduling 的都知道,我们用三种形式来部署计划任务,即 @Scheduled 注解的 fixedRate(fixedRateString), fixedDelay(fixedDelayString), 以及 cron. cron 不在这里讨论的范畴。我们着重在如何理解 fixedRate 和 fixedDelay 的区别。
在 Spring 的 Scheduled 注解的 JavaDoc 对此的解释很简单
public abstract long fixedRate
Execute the annotated method with a fixed period in milliseconds between invocations.
public abstract long fixedDelay
Execute the annotated method with a fixed period in milliseconds between the end of the last invocation and the start of the next.只是说是 fixedRate 任务两次执行时间间隔是任务的开始点,而 fixedDelay 的间隔是前次任务的结束与下次任务的开始。
大致用示意字符串来表示如下(每个 T1, 或 T2 代表任务执行秒数(每次任务执行时间不定),假定 fixedRate 或 fixedDelay 的值是 5 秒,用 W 表示等待的数)
fixedRate: T1.T1WWWT2.T2.T2WW.T3.T3.T3.T3.T3.T4.T4.T4.T4.T4.T4.T4T5T5WWWT6.T6........
fixedDelay: T1.T1.WWWWW.T2.T2.T2WWWWW.T3.T3.T3.T3.T3.WWWWW.T4.T4.T4.T4.T4.T4.T4.WWWWWT6.T6......
一般来说能理解到上面两个场景已经差不多了,相比而言 fixedDelay 简单些,盯着上一次任务的屁股就行。 Read More
昨日刚刚体验了 Terraform 是一个什么鬼东西 Terraform 使用 - 从最简单例子开始,今天再进一步。将来尝试的是使用 Terraform 来部署一个 Lambda 应用,并创建相关的资源。
本例中的 Lambda 要由 Kinesis 来触发,并写数据到 S3 Bucket 中去,所以需要做的事情大致如下:- 创建 IAM Role, 该 Role 要能访问 S3, Kinesis 和 CloudWatch
- 创建一个 Kinesis Stream (指定 Shard 数目)
- 创建一个 S3 Bucket
- 部署 Lambda (要指定能访问 S3 Bucket 的 Role, 并其他参数,如环境变量)
- 设置 Lambda 的 Kinesis 触发器 (指定源 Kinesis Stream 和 batchSize)
以下是 Lambda 的实现代码,从 Kinesis 读出字符串,逗号分割,第一部分作为 S3 Key, 第二部分作为文件内容写入到 S3 Bucket 中去。S3 Bucket 名称从环境变量中读取。 Read More