Java 单元测试最趁手的 Mock 组件当属 Mockito,虽然它最初是基于继承来实现 Mock 的,所以对私有方法,私有属性,静态方法, final 类,final 方法,构造函数无能为力。于是有时不得不引入 JMockit 或 PowerMockit 来辅助。不过现在的 Mockito 功力有所增强。
首先是 Mockito 2.1.0 开始可以 Mock final 类和 final 方法,要在 classpath 下创建个文件mockito-extensions/org.mockito.plugins.MockMaker, 内容为mock-maker-inline。 之前写过一篇介绍:Mockto 也能 Mock final 类和 final 方法了,其中也探索了它的实现细节,使用到了 ByteBuddy 修改字节码。
从 Mockito 3.4.0 通过类似的 mockto-extensions 扩展的方式,实现了对静态方法的 Mock。所有使用到的接口是 org.mockito.MockedStatic, 它当前在 Mockito 3.7.7 中还是一个试验性方法 @Incubating,能拿来用就行。 Read More
使用 Mockito Mock 方法式,一直以为可以用anyString(),any(Foo.class)等匹配null值,其实不行,null值必须显式的用null, 或eq(null)来匹配。anyString(),anyInt()等只能匹配非null值,查看它们的返回值实际是 "" 和 0 等, 而更为特别的是any(Foo.class)看到的是null, 仍然不能匹配null值。进一步用Mockito.mockingDetails(mock).printInvocations()打印出的内容,anyString(),any(Foo.class)都会显示为null值。
说的有点罗嗦,看下面的例子, 被测试类 UserDao,sql 和 sqlArguments 由各自的 setter 方法来控制,默认它们都为nullRead More
Java 多线程编程常用的一个接口是ExecutorService, 其实就一个线程池的接口,一般由两种方式创建线程池,一为 Executors 的工厂方法,二则创建 ForkJoinPool 实例,当然也有直接使用 ThreadPoolExecutor 的。
关于什么时候用ForkJoinPool或普通的线程池(如 Executors.newFixedThreadPool(2) 或 new ThreadPoolExecutor(...)) 不过多的述说。如果要运用到 ForkJoinTask 的话就要用 ForkJoinPool, 它是 Java7 新引入的线程池类型。
关于 Java7 的 fork-join 框架可参考很多年前的一篇 Java 的 fork-join 框架实例备忘。ForkJoinPool 的一个典型特征是能够进行 Work stealing。它也是 Akka actor 效率高效的一个有力保证。
本文只能某一种情形下在选择普通线程池与 ForkJoinPool 的区别,直接说吧,普通线程更容易造成死锁,而 ForkJoinPool 却能应对相同的状况。 Read More
承接近两年前的 用 PreparedStatement 向 SqlServer 中一次性插入多条记录,其文后用 User-Defined Type 可用下面简单的代码把 Java 本地内存中表格数据一股脑的刷入到 SQL Server 数据库表格中
String sql = "INSERT INTO Customers SELECT * FROM ?";
SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) conn.prepareStatement(sql);
SQLServerDataTable dataTable = ..... // 生成好的本地表格数据
pstmt.setStructured(1, "CustomersTableType", dataTable);
pstmt.execute();上面的 dataTable 本地表格类型变量容易生成,关键是必须在正式数据库数须预先用
CREATE TYPE创建好CustomersTableType这个用户自定义类型,这会受权限的约束。如果由 DBA 预先完全依照目标表来创建好这个用户自定义类型,又无法确定是否总是要操作该目标表的所有字段。数据库是允许我们创建临时的用户自定义类型 Read More

现实中有这样的用法,创建一批在线程池中运行的 CompletableFuture 实例,然后等待它们全部执行完再继续后面的操作。比如说 AWS 的 Lambda, 单单提交任务到线程池,不等待所有任务全部完成便退出主线程的话,AWS 便认为 Lambda 执行完毕,无视线程池中正在执行的任务而强行结束该 Lambda 实例。
以往我们通常的作法如下
1ExecutorService threadPool = Executors.newFixedThreadPool(10); 2List<CompletableFuture<Void>> futures = IntStream.rangeClosed(1, 10000) 3 .mapToObj(n -> 4 CompletableFuture.runAsync(() -> { 5 System.out.println("done " + n); 6 }, threadPool)).collect(toList()); 7 8futures.forEach(CompletableFuture::join); 9 10System.out.println("all done");如果所有的任务均无异常,上面的代码能得到预想的结果,只要上面打印出
all done的话真的就是表明所有的任务都完成了。但是在循环 joinfutures中的每一个 CompletableFuture 时,只要碰到任意一个任务有异常时,便立即抛出给外部线程,不在乎是否还有其他任务正在执行。此时,如果外部未予捕获,当然 Read More
在进行数据流处理过程中,需要一个高效苗条的流处理组件,比如对输入流能进行分组(窗口),能进行流量控制(Back Pressure - 背压),这也就涉及到响应式编程,流处理框架。这方面如果直接基于 Akka actor 来构建 Akka ActorSystem 也是比较复杂,依赖的组件也不少。还有构筑在 Akka actor 之上的 Akka Streams,再往上的 Flink Streaming,它们都有像滑动,滚动窗口的概念,但是依赖更不得了。一个基本的 Flink Streaming 的项目会依赖到 45 M 以上的第三方组件,如果用它来写一个数据流处理的共享组件,那真是要命。Spring 5 也开始带上了自己的 Reactive-Streams 实现 Spring Reactor, 想要把它从 Spring 中单独抽离出也非易事。Flink Streaming 组件依赖:org.apache.fling:flink-streaming-java_2.12:1.80, 会依赖于其他诸如 akka-stream, akka-actor, flink-core, flink-clients, scala-library 等非常多的东西
而另一个著名的响应式框架 RxJava 2 就清爽多了,完全没有第三方依赖,要说有也就是定义了四个接口的 reactive-streams(2 KB 大小),就自身那个 rxjava-2.2.9.jar 包只有 2.3 M,这才叫轻量级。因为它设计来是能被应用于 Android 客户端应用的,Andriod 上的 rxandriod-1.2.1.aar 只有 9 K。所以 RxJava 2.x 太适合用来写一些小的共享组件了。 Read More
在我们对数据库 DAO 类进行单元测试时,通常不应该依赖于一个外部数据库,所以会选用特定比较接近于真实数据库类型的内存或嵌入式数据库,如 HSQLDB(HyperSQL), H2, Derby 等。但总难免会用到特定数据库的特性,这时候就无法用前述各种数据库进行测试了。非要单元测试中覆盖到所用的数据库特性的话可以选择用 docker,如 Testcontainers, 经过模块扩展,它可以由 docker 来启动许多种类型的数据库,MySQL, Postgres, Oracle-XE, MS SQL Server, Couchbase 等等,详情见 Database containers。刚了解到的是它的模块化的无限可能,像支持 Kafka Containers 和 Localstack Module 等。
这里就不走 Testcontainers 那条路 -- 要求构建服务器上也要有 docker。早先希望能找到一种嵌入式或内存 PostgreSQL 数据库,后来发现 PostgreSQL 未能提供 In-Process 和 In-Memory 的启动方式,好在 PostgreSQL 是开源,有人可以把它改造为小型的可由测试代码启停的本地数据库。有两个具有代表性的组件,分别是 OpenTable Embedded PostgreSQL Component 和 Embedded PostgreSQL Server,它们都号称是 Embedded,所谓嵌入式,其实是进测试进程外的数据库。
下面简单体验下两个组件的用法 Read More
- 写 Java 代码至今,在应对可能冲突的共享资源操作时会尽量用 JDK 1.5 开始引入的并发锁(如 Lock 的各类实现类, ReentrantLock 等) 进行锁定,而不是原来的
synchronized关键字强硬低性能锁。
这里是应用 JDK 1.5 的Lock的基本操作步骤private Lock lock = new ReentrantLock(); private void operate() {
如此,
// 安全操作 ....
lock.lock();
try {
// 对共享资源的操作 ...
} finally {
lock.unlock();
}
}operate()就是一个线程安全的方法,任何对它的调用都安排到了一个队列里等着。但有时候上锁需要考虑更细的粒度,下面是一个演示案例,引出第一个问题
Read More JSON 表示布尔值标准的形式是
true和false,如果 Java 对应的类型是对象 Boolean,那么在 JSON 中也可以是null。如果收到 JSON 数据是用 'Y'/'N', 或 'Yes'/'No' 来表示布尔值的,那么使用 Java 的 Jackson 库如何把它们反序列化为相应的布尔属性值呢?如果按照 JSON 规范必须把内容中的布尔值全部转换为
true或false, 然而再反序列化,否则需要定制Boolean类型的反序列化类,可应用到全局的 boolean 类型,或指派给特定的 boolean 类型属性。如果尝试反序列化
Y, 或N为 Java 的 boolean 值,会有只接受 true 或 false 的异常:com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not deserialize value of type java.lang.Boolean from String "Y": only "true" or "false" recognized
具体步骤是: Read More
如果一个 Java 类在初始化时会有外部依赖,这就给单元测试创建它的实例时造成困难。当然被测试类可以改造为依赖全部构造时注入或创建实例后延迟注入,这里不考虑这种改造。
可以参看我以前一篇类似的日志:使用 JMockit 来 mock 构造函数
来说下面的例子1public class OrderService { 2 private PriceInquiry priceInquiry = new PriceInquiry(); 3 ......... 4 5 public double totalPrice() { 6 return priceInquiry.retrieve(....); 7 } 8}
假如上面的代码是不能改动的,并且在new PriceInquiry()时依赖于网络环境,所以单机情况不能创建成功。也就使得测试时试图new OrderService();
会失败。并且试图用 Mockito 的@InjectMocks也不行 Read More