Friday, 2 November 2018

HSQL DB custom function to mimic the DB function that HSQL not support (compatibility issue)



It is a solution say when we do integration test using Hyper SQLDB, if the SQL statement have functions which in-memory DB not support, we can use Java Language Routines to mimic the logic the specific-DB-function performs.

An examples is if the specific DB is SQL Server, and the SQL statement has LEN() function which will return the length of the varchar, in SQL Server, however, HSQLDB not support LEN() function (only support length()), and also we will not write a specific SQL for HSQLDB for testing purpose, in this case, we can use Java Language Routines which is a static method of a Java class, specified with a fully qualified method name in the routine definition.

Step 1: define a Java class and a static method to mimic the function you need
               For this case, I need a method by providing a string and return the length of string, so the method may look like below:

   public class JavaRoutinesForHSql {

   public static int stringLength(String chars){
      if (chars!=null)
         return chars.trim().length();
      return 0;
   }
}


Step 2: define the routine in sql script
             Before the SQL statement is called, create the function as below:     




Step 3:  you can drop the custom routine if needed:

               DROP SPECIFIC ROUTINE LEN;




Tuesday, 7 August 2018

DDD: domain driven design and dependency injection

I agree that having a reference to Services, Repositories and Factories from Entities is NOT good. This is the most accepted opinion. Even though Repositories and Factories are citizens of the Domain layer, they are not part of the problem domain. Sometimes (e.g. in the Wikipedia article on the DDD) the concept of the Domain services is called Pure Fabrication which implies that the class (Service) "does not represent a concept in the problem domain". I'd rather refer to Factories and Repositories as Pure Fabrications, because Eric Evans does say something else in his book about the concept of Services:
But when an operation is actually an important domain concept, a SERVICE forms a natural part of a MODEL-DRIVEN DESIGN. Declared in the model as a SERVICE, rather than as a phony object that doesn't actually represent anything, the standalone operation will not mislead anyone.
According to the above-said, sometimes calling a Service from Your Entity might be a sane thing to want. Then, You can use the Double Dispatch approach, so that You won't have to keep a reference to the Service in Your Entity class.
Of course, there are always some people who disagree with the mainstream opinion like the author of Accessing Domain Services from Entities article.
An example is for the entity class User, we define a method which has a argument of a service instance:

    public interface UserService
    {
        List<User> findSameLastName(string lastName);
    }

    public class User
    {
        private String lastName;
        //...

        public List<User> findByLastName(UserService userService)
        {
            return userService.findSameLastName(this.lastName);
        }
    }

We do not need to inject IUserService into the User model but introduced as a method argument, because normally this method is invoked by upper layer, say UI layer controller, if we user Spring Framework, in controller we can autowire the userService and then call findByLastName method provide the service instance:
@RestController
public UserController {
    @Autowired
    private UserService userServiceImpl;
    // ...
    @RequestMapping(...)
    private void aMethod(){
    // say we have a user instance from Request...
   List<User> users = user.findByLastName(userServiceImpl); // here is the magic :)
    }
}



Sunday, 27 May 2018

DDD - Domain Driven Design - The key of microservie is not tech-arch but how to split business and define BC stuff

领域驱动的火爆程度不用我赘述,但是即便其如此得耳熟能详,但大多数人对其的认识,还只是停留在知道它的缩写是DDD,知道它是一种软件思想,或者知道它和微服务有千丝万缕的关系。Eric Evans对DDD的诠释是那么地惜字如金,而我所认识的领域驱动设计的专家又都是行业中的资深前辈,他们擅长于对软件设计进行高屋建瓴的论述,如果没有丰富的互联网从业经验,是不能从他们的分享中获取太多的营养的,可以用曲高和寡来形容。1000个互联网从业者,100个懂微服务,10个人懂领域驱动设计。
可能有很多和我一样的读者,在得知DDD如此火爆之后,尝试去读了开山之作《领域驱动设计——软件核心复杂性应对之道》,翻看了几张之后,晦涩的语句,不明所以的专业术语,加上翻译导致的语句流畅性,可以说观看体验并不是很好,特别是对于开发经验不是很多的读者。我总结了一下,为何这本书难以理解:
1. 没有阅读软件设计丛书的习惯,更多人偏向于阅读偏应用层面的书籍,“talk is cheap,show me the code”往往更符合大多数人的习惯。
2. 没有太多的开发经验支撑。没有踩过坑,就不会意识到设计的重要性,无法产生共情。
3. 年代有些久远,这本书写于2004年,书中很多软件设计的反例,在当时是非常流行的,但是在现在已经基本绝迹了。大师之所以为大师,是因为其能跨越时代的限制,预见未来的问题,这也是为什么DDD在十几年前就被提出,却在微服务逐渐流行的现阶段才被大家重视。
诚然如标题所示,本文是领域驱动设计的一个入门文章,或者更多的是一个个人理解的笔记,笔者也正在学习DDD的路上,可能会有很多的疏漏。如有理解有偏颇的地方,还望各位指摘。
认识领域驱动设计的意义
领域驱动设计并不会绝对地提高项目的开发效率。 
图1:复杂性与开发周期关系

遵循领域驱动设计的规范使得项目初期的开发甚至不如不使用它来的快,原因有很多,程序员的素质,代码的规范,限界上下文的划分…甚至需求修改后导致需要重新建模。但是遵循领域驱动设计的规范,在项目越来越复杂之后,可以不至于让项目僵死。这也是为什么很多系统不断迭代着,最终就黄了。书名的副标题“软件核心复杂性应对之道”正是阐释了这一点。

模式: smart ui是个反模式
可能很多读者还不知道smart ui是什么,但是在这本书写作期间,这种设计风格是非常流行的。在与一位领域驱动设计方面的资深专家的交谈中,他如下感慨到软件发展的历史:
2003年时,正是delphi,vb一类的smart ui程序大行其道,Java在那个年代,还在使用jsp来完成大量的业务逻辑操作,4000行的jsp是常见的事;2005年spring hibernate替换了EJB,社区一片欢呼,所有人开始拥护action,service,dao这样的贫血模型(充血模型,贫血模型会在下文论述);2007年,Rails兴起,有人发现了Rails的activeRecord是涨血模型,引起了一片混战;直到现在的2017年,微服务成为主流系统架构。
在现在这个年代,不懂个MVC分层,都不好意思说自己是搞java的,也不会有人在jsp里面写业务代码了
(可以说模板技术freemarker,thymeleaf已经取代jsp了),
但是在那个年代,还没有现在这么普遍地强调分层架构的重要性。
这个章节其实并不重要,因为mvc一类的分层架构已经是大多数java初学者的“起点”了,大多数DDD的文章都不会赘述这一点,我这里列出来是为了让大家知晓这篇文章的时代局限性,在后续章节的理解中,也需要抱有这样的逻辑:这本书写于2004年。
模式: Entity与Value Object
我在不了解DDD时,就对这两个术语早有耳闻。entity又被称为reference object,我们通常所说的Java bean在领域中通常可以分为这两类,(可别把value object和常用于前台展示的view object,vo混为一谈)
entity的要义在于生命周期和标识,value object的要义在于无标识,通常情况下,entity在通俗意义上可以理解为数据库的实体,(不过不严谨),value object则一般作为一个单独的类,构成entity的一个属性。
举两个例子来加深对entity和value object的理解。
例1:以电商微服务系统中的商品模块,订单模块为例。将整个电商系统划分出商品和订单两个限界上下文(Bound Context)应该是没有争议的。如果是传统的单体应用,我们可以如何设计这两个模块的实体类呢?
会不会是这样?
复制代码
class Product{
    String id;//主键
    String skuId;//唯一识别号
    String productName;
    Bigdecimal price;
    Category category;//分类
    List<Specification> specifications;//规格 
    ... 
}

class Order{
    String id;//主键
    String orderNo;//订单号
    List<OrderItem> orderItems;//订单明细
    BigDecimal orderAmount;//总金额
    ...
}

class OrderItem{
    String id;
    Product product;//关联商品
    BigDecimal snapshotPrice;//下单时的价格
}
复制代码

看似好像没问题,考虑到了订单要保存下单时候的价格(当然,这是常识)但这么设计却存在诸多的问题。
在分布式系统中,商品和订单这两个模块必然不在同一个模块,也就意味着不在同一个网段中。
上述的类设计中直接将Product的列表存储到了Order中,也就是一对多的外键关联。这会导致,每次访问订单的商品列表,都需要发起n次远程调用
反思我们的设计,其实我们发现,订单BC的Product和商品BC的Product其实并不是同一个entity,在商品模块中,我们更关注商品的规格,种类,实时价格,这最直接地反映了我们想要买什么的欲望。而当生成订单后,我们只关心这个商品买的时候价格是多少,不会关心这个商品之后的价格变动,还有他的名称,仅仅是方便我们在订单的商品列表中定位这个商品。
如何改造就变得明了了
复制代码
class OrderItem{
    String id;
    String productId;//只记录一个id用于必要的时候发起command操作
    String skuId;
    String productName;
    ...
    BigDecimal snapshotPrice;//下单时的价格
}
复制代码

是的,我们做了一定的冗余,这使得即使商品模块的商品,名称发生了微调,也不会被订单模块知晓。这么做也有它的业务含义,用户会声称:我买的时候他的确就叫这个名字。记录productId和skuId的用意不是为了查询操作,而是方便申请售后一类的命令操作(command)。
在这个例子中,Order 和 Product都是entity,而OrderItem则是value object(想想之前的定义,OrderItem作为一个类,的确是描述了Order这个entity的一个属性集合)。关于标识,我的理解是有两层含义,第一个是作为数据本身存储于数据库,主键id是一个标识,第二是作为领域对象本身,orderNo是一个标识,对于人而言,身份证是一个标识。而OrderItem中的productId,id不能称之为标识,因为整个OrderItem对象是依托于Order存在的,Order不存在,则OrderItem没有意义。
例子2: 汽车和轮胎的关系是entity和value object吗?
这个例子其实是一个陷阱题,因为他没有交代限界上下文(BC),场景不足以判断。对于用户领域而言,的确可以成立,汽车报废之后,很少有人会关心轮胎。
轮胎和发动机,雨刮器,座椅地位一样,只是构成汽车的一些部件,和用户最紧密相关的,只有汽车这个entity,轮胎只是描述这个汽车的属性(value object);
场景切换到汽修厂,无论是汽车,还是轮胎,都是汽修厂密切关心的,每个轮胎都有自己的编号,一辆车报废了,可以安置到其他车上,这里,他们都是entity。
这个例子是在说明这么一个道理,同样的事物,在不同的领域中,会有不同的地位。 
图2:《领域驱动设计》Value Object模式的示例
在单体应用中,可能会有人指出,这直接违背了数据库范式,但是领域驱动设计的思想正如他的名字那样,不是基于数据库的,而是基于领域的
微服务使得数据库发生了隔离,这样的设计思想可以更好的指导我们优化数据库。

模式: Repository
哲学家分析自然规律得出规范,框架编写者根据规范制定框架。有些框架,可能大家一直在用,但是却不懂其中蕴含的哲学。

——来自于笔者的口胡
记得在刚刚接触mvc模式,常常用DAO层表示持久化层,在JPA+springdata中,抽象出了各式各样的xxxRepository,与DDD的Repository模式同名并不是巧合,
jpa所表现出的正是一个充血模型(如果你遵循正确的使用方式的话),可以说是领域驱动设计的一个最佳实践。
开宗明义,在Martin Fowler理论中,有四种领域模型:
1. 失血模型
2. 贫血模型
3. 充血模型
4. 胀血模型
详细的概念区别不赘述了,可以参见专门讲解4种模型的博客。他们在数据库开发中分别有不同的实现,用一个修改用户名的例子来分析。
class User{
    String id;
    String name;
    Integer age;
}
失血模型:
跳过,可以理解为所有的操作都是直接操作数据库,在smart ui中可能会出现这样的情况。
贫血模型:
复制代码
class UserDao {
    @Autowired
    JdbcTemplate jdbcTemplate;

    public void updateName(String name,String id){
        jdbcTemplate.excute("update user u set u.name = ? where id=?",name,id);
    }
}

class UserService{

    @Autowired
    UserDao userDao;

    void updateName(String name,String id){
        userDao.updateName(name,id);
    } 
}
复制代码
贫血模型中,dao是一类sql的集合,在项目中的表现就是写了一堆sql脚本,与之对应的service层,则是作为Transaction Script的入口。
观察仔细的话,会发现整个过程中user对象都没出现过
充血模型:
复制代码
interface UserRepository extends JpaRepository<User,String>{
    //springdata-jpa自动扩展出save findOne findAll方法
}

class UserService{
    @Autowoird
    UserRepository userRepository;

    void updateName(String name,String id){
        User user = userRepository.findOne(id);
        user.setName(name);
        userRepository.save(user);
    }
}
复制代码
充血模型中,整个修改操作是“隐性”的,对内存中user对象的修改直接影响到了数据库最终的结果,不需要关心数据库操作,只需要关注领域对象user本身。Repository模式就是在于此,屏蔽了数据库的实现。与贫血模型中user对象恰恰相反,整个流程没有出现sql语句。
涨血模型:
没有具体的实现,可以这么理解:
void updateName(String name,String id){
    User user = new User(id);
    user.setName(name);
    user.save();
}

我们在Repository模式中重点关注充血模型。
为什么前面说:如果你遵循正确的使用方式的话,springdata才是对DDD的最佳实践呢?
因为有的使用者会写出下面的代码:
复制代码
interface UserRepository extends JpaRepository<User,String>{

    @Query("update user set name=? where id=?")
    @Modifying(clearAutomatically = true)
    @Transactional
    void updateName(String name,String id);
}
复制代码
历史的车轮在滚滚倒退。本节只关注模型本身,不讨论使用中的一些并发问题,再来聊聊其他的一些最佳实践。
复制代码
interface UserRepository extends JpaRepository<User,String>{

    User findById();//√  然后已经存在findOne了,只是为了做个对比
    User findBy身份证号();//可以接受
    User findBy名称();//×
    List<权限> find权限ByUserId();//×
}
复制代码
理论上,一个Repository需要且仅需要包含三类方法loadBy标识,findAll,save(一般findAll()就包含了分页,排序等多个方法,算作一类方法)。
标识的含义和前文中entity的标识是同一个含义,在我个人的理解中,身份证可以作为一个用户的标识(这取决于你的设计,同样的逻辑还有订单中有业务含义的订单编号,保单中的投保单号等等),在数据库中,id也可以作为标识。findBy名称为什么不值得推崇,因为name并不是User的标识,名字可能会重复,只有在特定的现场场景中,名字才能具体对应到人。
那应该如何完成“根据姓名查找可能的用户”这一需求呢?最方便的改造是使用Criteria,Predicate来完成视图的查询,哪怕只有一个非标识条件。
在更完善的CQRS架构中,视图的查询则应该交由专门的View层去做,可以是数据库,可以是ES
findByUserId不值得推崇则是因为他违背了聚合根模式(下文会介绍),
User的Repository只应该返回User对象。
软件设计初期,你是不是还在犹豫:是应该先设计数据库呢,还是应该设计实体呢?在Domain-Driven的指导下,你应当放弃Data-Driven。
模式 聚合和聚合根
难住我的还有英文单词,初识这个概念时,忍不住发问:Aggregate是个啥。文中使用聚合的概念,来描述对象之间的关联,采用合适的聚合策略,可以避免一个很长,很深的对象引用路径。对划分模块也有很大的指导意义。
在微服务中我们常说划分服务模块,在领域驱动设计中,我们常说划分限界上下文。在面向对象的世界里,用抽象来封装模型中的引用,聚合就是指一组相关对象的集合,我们把它作为数据修改的单元。每个聚合都有一个聚合根(root)和一个边界(boundary)。边界定义了聚合内部有什么,而根则是一个特定的entity,两个聚合之间,只允许维护根引用,只能通过根引用去向深入引用其他引用变量。
例子还是沿用电商系统中的订单和商品模块。在聚合模式中,订单不能够直接关联到商品的规格信息,如果一定要查询,则应该通过订单关联到的商品,由商品去访问商品规格。在这个例子中,订单和商品分别是两个边界,而订单模块中的订单entity和商品模块中的商品entity就是分别是各自模块的root。遵循这个原则,可以使我们模块关系不那么的盘根错节,这也是众多领域驱动文章中不断强调的划分限界上下文是第一要义。
模式 包结构
微服务有诸多的模块,而每个模块并不一定是那么的单一职责,比模块更细的分层,便是包的分层。
我在阅读中,隐隐觉得这其中蕴含着一层哲学,但是几乎没有文章尝试解读它。
领域驱动设计将其单独作为了一个模式进行了论述,篇幅不小。重点就是论述了一个思想:包结构应当具有高内聚性
这次以一个真实的案例来介绍一下对高内聚的包结构的理解,项目使用maven多module搭建。
我曾经开发过一个短信邮件平台模块,它在整个微服务系统中有两个职责,
一:负责为其他模块提供短信邮件发送的远程调用接口,
二:有一个后台页面,可以让管理员自定义发送短信,并且可以浏览全部的一,二两种类型发送的短信邮件记录。
在设计包结构之前,先是设计微服务模块。

api层定义了一系列的接口和接口依赖的一些java bean,model层也就是我们的领域层。
这两个模块都会打成jar包,外部服务依赖api,api则由app模块使用rpc框架实现远程调用。
admin和app连接同一个数据源,可以查询出短信邮件记录,admin需要自定义发送短信也是通过rpc调用。
简单介绍完了这个项目后,重点来分析下需求,来看看如何构建包结构。
module    desc                                                        packageType
api          api interfact to publish service                   jar
app         api implementation                                   executable jar
admin     admin application                                      executable jar
model     entities                                                     jar
mvc分层天然将controller,service,model,config层分割开,这符合DDD所推崇的分层架构模式(这个模式在原文中有描述,但我觉得和现在耳熟能详的分层结构没有太大的出入,所以没有放到本文中介绍),
而我们的业务需求也将短信和邮件这两个领域拆分开了。
那么,
到底是mvc应该包含业务包结构呢?
还是说业务包结构包含mvc呢?
mvc高于业务分层
//不够好的分层
aaa.message.admin
    config
        CommonConfig.java
    service
        CommonService.java
        mail
            MailTemplateService.java
            MailMessageService.java
        sms
            SmsTemplateService.java
            SmsMessageService.java
    web
        IndexController.java
        mail
            MailTemplateController.java
            MailMessageController.java
        sms
            SmsTemplateController.java
            SmsMessageController.java
    MessageAdminApp.java
业务分层包含mvc
复制代码
//高内聚的分层
aaa.message.admin
    config
        CommonConfig.java
    service
        CommonService.java
    web
        IndexController.java
    mail
        config
            MailConfig.java
        service
            MailTemplateService.java
            MailMessageService.java
        web
            MailTemplateController.java
            MailMessageController.java
    sms
        config
            Smsconfig.java
        service
            SmsTemplateService.java
            SmsMessageService.java
        web
            SmsTemplateController.java
            SmsMessageController.java
    MessageAdminApp.java
复制代码
业务并不是特别复杂,但应该可以发现第二种(业务分层包含mvc)的包结构,才是一种高内聚的包结构。
第一种分层会让人有一种将各个业务模块(如mail和sms)的service和controller隔离开了的感觉,当模块更多,每个模块的内容更多,这个“隔得很远”的不适感会逐渐侵蚀你的开发速度。
一种更加低内聚的反例是不用包分层,仅仅依赖前缀区分,由于在项目开发中真的发现同事写出了这样的代码,我觉得还是有必要拿出来说一说:
//反例
aaa.message.admin
    config
        CommonConfig.java
        MailConfig.java
        Smsconfig.java
    service
        CommonService.java
        MailTemplateService.java
        MailMessageService.java
        SmsTemplateService.java
        SmsMessageService.java
    web
        IndexController.java
        MailTemplateController.java
        MailMessageController.java
        SmsTemplateController.java
        SmsMessageController.java     
    MessageAdminApp.java
这样的设计会导致web包越来越庞大,逐渐变得臃肿,使项目僵化,项目经理为何一看到代码就头疼,
规范的高内聚的包结构,遵循业务>分层的原则,可以知道我们的项目庞大却有条理。
其他模式
《领域驱动设计》这本书介绍了众多的模式,上面只是介绍了一部分重要的模式,后续我会结合各个模式,尽量采用最佳实践+浅析设计的方式来解读。

微服务之于领域驱动设计的一点思考
技术架构诚然重要,但不可忽视领域拆解和业务架构,《领域驱动设计》中的诸多失败,成功案例的总结,是支撑其理论知识的基础,最终汇聚成众多的模式。在火爆的微服务架构潮流下,我也逐渐意识到微服务不仅仅是技术的堆砌,更是一种设计,一门艺术。我的本科论文本想就微服务架构进行论述,奈何功底不够,最后只能改写成一篇分布式网站设计相关的文章,虽然是一个失败的过程,但让我加深了对微服务的认识。如今结合领域驱动设计,更加让我确定,技术方案始终有代替方案,决定微服务的不是框架的选择,不仅仅是restful或者rpc的接口设计风格的抉择,而更应该关注拆解,领域,限界上下文,聚合根等等一系列事物,这便是我所理解的领域驱动设计对微服务架构的指导意义。

Friday, 26 January 2018

web layer unit test and integration test in Spring

There are different ways to test your Controller (Web or API Layer) classes in Spring Boot, some provide support to write pure Unit Tests and some others are more intended to be used for Integration Tests. Within this post, I’ll cover the main three test approaches available for Spring: using MockMVC in standalone mode, MockMVC together with SpringRunner, and using SpringBootTest.

Introduction

There are a few different approaches to testing available in Spring Boot. It’s a framework that’s constantly evolving, so more options arise in new versions at the same time that old ones are kept for the sake of backward compatibility. The result: multiple ways of testing the same part of our code, and some unclarity about when to use what. Within this post, I’ll help you understand the different alternatives, the reasons why they are available and when it’s better to use each one.
This article focuses on Controller testing since it’s the most unclear part, where mocking objects is possible at different levels.

The sample application

In summary, it’s just a repository of entities -superheroes- exposed through a REST API. It’s important to list also some particularities of the application to further understand what happens when using the different strategies:
  • If a superhero can’t be found by their identifier, a NonExistingHeroException is thrown. There is a Spring’s @RestControllerAdvice that will intercept that exception and transform it into a 404 status code – NOT_FOUND.
  • There is a SuperHeroFilter class that will be used in our HTTP communication to add a header to the HTTP Response: X-SUPERHERO-APP.

Server and Client Side Tests

To start with, we can separate server-side and client-side tests. Server-side tests are the most commonly used: you perform your request and you want to check how the server behaves, how the response is formed, what are the retrieved contents, etc.
The client-side tests are not so common, they are useful when you want to verify that an indirect request has been made: you mock the server behavior and then you call some code (on your side) that indirectly will perform a request to that server. That’s exactly what you want to test, that the request has been made and the contents of your request were made, you don’t care about the response since you mocked it. Too bad there are not many good examples of this. Even if you check the official examples, they are not so helpful (see the Javadoc comments). Anyways, the important idea here is that they can be used when you’re writing a client application and you want to verify the requests from your side to the outside world.
We’ll focus on server-side Tests, which are the ones to verify how the server logic works. In this case, the requests are normally mocked, and you want to check how your server logic reacts. These kind of tests are tightly related to the Controller layer in your application since it’s the part in Spring that takes care of handling the HTTP requests.

Server-Side Tests

If we zoom inside server-side tests, there are two main strategies we can identify in Spring: writing Controller tests using the MockMVC approach, or making use of RestTemplate. The first strategy (MockMVC) should be your preferred one if you want to code a real Unit Test, while RestTemplate should be used if you intend to write an Integration Test. The reason is that with MockMVC we can fine-grain our assertions for the Controller. RestTemplate, on the other hand, will use the Spring’s WebApplicationContext (partly or fully, depends on using the Standalone mode or not). Let’s explain these two strategies in more detail.

Inside-Server Tests

We can test directly our Controller logic without needing a web server to be running. That’s what I call inside-server testing, and it’s closer to the definition of a Unit Test. To make it possible, you need to mock the entire web server behavior, so somehow you’re missing parts to be tested in our application. But don’t worry, because those parts can be perfectly covered with an Integration Test.

Strategy 1: MockMVC in Standalone Mode

Test MockMVC Standalone
In Spring, you can write an inside-server test if you use MockMVC in standalone mode, so you’re not loading any context. Let’s see an example of this.
These are the main parts of this code that we need to focus on:
  • We use the MockitoJUnitRunnerto run our unit test. This one is provided by Mockito and adds some functionality on top of the built-in JUnit runner: detects that the framework is being used, that here are no unused stubs, and initializes for us all the fields annotated with @Mock, so we don’t need to call Mockito.initMocks()method.
  • Note how we initialize the mocks: our SuperHeroRepository is mocked as usual with the annotation and, since we need it inside our controller class, we annotate our SuperHeroController instance with @InjectMocks, so it’s initialized and the mocked repository is injected in it.
  • JacksonTesterobject is also injected here automatically by using the JacksonTester.initFields()method below. This utility class comes with Spring and it’s initialized using a static method as you can see, so it’s kind of tricky.
  • In the setup method, which is executed before every test, we need to configure Mockito in Standalone mode and explicitly configure our Controller under test, the Controller Advice and our HTTP Filter. We could add the advice and the filter parts to a base class but, in any case, you can see already the main disadvantage of this approach: any part of your logic that is modeled within ControllerAdvice’s, Filters, etc., needs to be configured here since you don’t have any Spring context that can inject them automatically.
  • For each test, we use our MockMVC instance to perform all kind of fake requests (GET, POST, etc.) and we receive a MockHttpServletResponse in return. Keep in mind that’s not a real response either, everything is being simulated.
  • Pay attention to how we can verify our surrounding stuff: in line 60 we check that a request with an unexisting id ends up in a NOT_FOUND code, so the ControllerAdvice is working fine. We also have a test method to verify that the header is present, so our Filter is also doing its work. You can do a quick exercise with this code: remove the part of the standalone setup in which we specified the advice and the filter, and run the test again. As expected, it would fail in that case since there is no context to inject these classes.
For the sake of the educational purpose of this post, I included in this test the Filter and the ControllerAdvice. But we could decide not to do that, and leave the tests that verify the presence of the header and the 404 status code to an integration test (so we remove them from here and from the standalone configuration). If we do that we have a pure version of Unit Test: we are testing only the Controller class logic, without any other interference.

Strategy 2: MockMVC with WebApplicationContext

Test MockMVC with Context
The second strategy we can use to write Unit Tests for a Controller also involves MockMVC, but in this case we can load a Spring’s WebApplicationContext.  Since we’re still using an inside-server strategy, there is no web server deployed in this case though.
When compared with the Standalone mode, these are the main differences:
  • The test is executed with SpringRunner, that’s how the context – or part of it – is initialized. When you run the test, you can see at the beginning of the trace how the context starts loading and the injected beans.
  • With the @WebMVCTest annotation our MockMVC instance gets autoconfigured and available in the context (so we can autowire it as you see below in the code). Besides, we specify in the annotation the controller class we want to test so only a partial Spring context will be loaded (the controller and its surrounding configuration). The annotation implementation is smart enough to know that our Filter and the Controller Advice should be also injected so, in this case, there is no explicit configuration in the setup() method.
  • Now the repository is injected in the Spring’s context using @MockBean. We don’t need to make any reference to our controller class apart from the one in the annotation, since the controller will be injected and available.
  • Bear in mind that the responses we’re verifying are still fake. There is no web server involved in this test either. In any case, it’s a perfectly valid test since we’re checking our logic inside our class and, at the same time, some surrounding actors (SuperHeroExceptionHandler and SuperHeroFilter).
The most important difference is that we didn’t need to explicitly load the surrounding actors, since there is a Spring’s context in place. If we create new filters, new controller advices, or any other actor participating in the request-response process, it will get automatically injected in our test so we don’t need to take care of the manual configuration here. There is no fine-grain control of what to use in our test, but it’s closer to what happens in reality: when we load our application, all this stuff gets automatically injected and configured.
You can see here a small transition to what some people could say it’s an integration test. In this case, we’re testing the filter and the controller advice out-of-the-box without making any reference to them. If we include in the future any other class intervening the request-response flow, it would participate in this test as well. Since more than a class’ behavior is included here, you could classify it as an Integration Testbetween those classes. The line is blurry though: on the other hand, you could argue that there is only one Controller being tested here, but you need the extra configuration provided by those classes to have the full behavior of it.

Outside-Server Tests

When you perform an HTTP request to your application to test it, you’re running what I call an outside-server test. However, even being outside you can inject mocks also in these tests, so you could get something similar to a Unit Test also in this case. For instance, in a classical 3-layered application, you could mock the Service layer and test only your Controller through a web server. But, in practice, this approach is much heavier than a normal Unit Test: you’re loading the entire application context unless you tell Spring not to do so during the test (by excluding configuration or only including what you need).
In Spring you can write outside-server tests for REST controllers using a RestTemplate to perform your requests, or the new TestRestTemplate which includes some useful features for integration testing (ability to include authentication headers and fault tolerance). More specifically, in Spring Boot you can also use the @SpringBootTest annotation, and then you can get some of these beans injected in your context, access to the properties loaded from application.properties, etc., out-of-the-box. It’s an alternative to @ContextConfiguration (Spring) that gives you all the Spring Boot features for your test.
Testing Strategies in Spring Boot can be confusing given the number of features and available shortcuts. Let’s have a look at those strategies as we did for MockMVC.

Strategy 3: SpringBootTest with a MOCK WebEnvironment value

If you use @SpringBootTest or @SpringBootTest(webEnvironment = WebEnvironment.MOCK) you don’t load a real HTTP server. Sounds familiar? It’s a similar approach to the strategy 2 (MockMVC with an application context).
So, in theory we were intending to use @SpringBootTest annotation to write an outside-server test but, when we set the WebEnvironment to MOCK, we’re converting it to an inside-server test. We can’t use a RestTemplate since we don’t have any web server, so we need to keep using MockMVC, which now is getting configured thanks to the extra annotation @AutoconfigureMockMVC. This is the trickiest approach between all the available ones in my opinion, and I personally discourage using it. Better go for Strategy 2 with MockMVC and the context loaded for a specific controller: you’ll be more in control of what you’re testing.

Strategy 4: SpringBootTest with a Real Web Server

Spring Boot Test
Spring Boot Test
When you use @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) or @SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT) you’re testing with a real HTTP server so, in this case, you need to use a RestTemplate or TestRestTemplate. The difference between using a random port or a defined port is just that in the first case the default port 8080 (or the one you override with the server.port property) won’t be used but replaced with a randomly-assigned port number. This is helpful when you want to run parallel tests, to avoid port clashing.
Let’s have a look at the code and then describe the main characteristics.
Can you spot the differences?
  • We use the SpringRunner to run our test but we annotate it with @SpringBootTest specifying the RANDOM_PORT mode. Just by doing that, we’ll get a web server up and running for our tests.
  • Note that we’re still mocking the repository layer with @MockBean annotation.
  • We have a TestRestTemplate bean that we can inject because we’re using @SpringBootTest . It behaves exactly the same as a standard RestTemplate, but has some extra functionalities as seen before.
  • Our requests are now performed using the template (line 18), same as we were trying to reach an external server.
  • The assertions change now a little bit since the response we want to verify is now a ResponseEntity instead of a MockHttpServletResponse.
Even though our goal is the same – testing the Controller layer, this test approaches the solution from a totally different angle from the one in Strategy 1 (MockMVC in standalone mode). While in there we were just loading our class and not even the surrounding actors (filter and controller advice), we’re here loading the entire Spring Boot context with the web server included. This approach is the heaviest of all, and the most distant to the concept of a Unit Test.
This strategy is mainly intended for Integration Tests. The idea is that you can still mock beans and replace those in the context but you can verify interactions between different classes in your Spring Boot application, with the web server participating as well. My advice: don’t use this strategy for Unit Tests, you’re making it fat and you may lose control of what you’re testing unitarily. But don’t take me wrong: favor this approach for Integration Tests and always include that testing layer in your application, verifying how your different components work together.

Performance and Context Caching

You may think that the Strategy 1 is much more optimal in performance than others; and that Strategy 4 may perform terribly if you need to load the entire Spring Boot Context every time you run a test. Well, that’s not entirely correct. When you use Spring (including Boot) for testing, the application context will be reused by default during the same Test Suite. That means, in our case, that Strategies 2, 3 and 4 are reusing the Spring context after it’s loaded for the first time.
Be aware that context reuse might cause some side effects if your tests are modifying beans included in the context. If that’s your case, you’ll need to do some tricks with the @DirtiesContextannotation and indicate that you want to reload the context.

Conclusion

As we saw, you have many alternatives to test unitarily your Controllers in Spring Boot. We covered from the lightest to the heaviest one.
It’s time to give you some personal advice about when to use what:
  • Try always to write Unit Tests for your Controller logic without focusing on any other behavior, so in general go for Strategy 1: use MockMVC in Standalone mode.
  • If you need to test some surrounding behavior related to the Web Layer, such as filtering, interceptors, authentication, etc., then choose Strategy 4: SpringBootTest with a web server on a random port. But manage it as a separate Integration Test since you’re verifying several parts of your application, and don’t miss the Unit Test for the pure Controller layer if you need it (so try to avoid mixing the test layers and keep them separate).