在Spring中,可以在Standalone模式下使用MockMVC来进行服务内测试,此时我们不会加载任何Context。来看个例子: MockitoJUnitRunner和MockMVC 代码中使用了MockitoJUnitRunner来运行单元测试。这个类是由Mockito提供的,并在内置的JUnit Runner上添加了一些功能:比如检测框架运行,初始化所有用@Mock注解声明的变量,这样就不需要再调用Mockito.initMocks()方法来显式mock对象了了。 代码中使用@Mock注解mock了一个IWorkerService的实例。这个IWorkerService的实例需要注入到WorkerController类的实例中。所以我们在声明WorkerController实例的时候使用了@InjectMocks注解。这样,通过这个注解我们使用mock出的IWorkerService实例替换了真正的WorkerServiceImpl实例。 在每个测试中,我们使用MockMvc对象来执行各种各样的模拟请求(如GET、POST等请求),之后我们也会收到一个MockHttpServletResponse对象作为返回值。注意这个返回值也不是一个真正的返回值,也是模拟的。 JacksonTester初始化 代码中使用JacksonTester.initFields()方法创建了一个JacksonTester对象。JacksonTester是Spring提供的一个工具类,可以使用这个JacksonTester对象来生成Worker实例的json字符串。 配置standalone MockMVC实例 每个测试在执行前都会调用setup方法。在setup方法中我们采用Standalone模式创建了MockMVC实例,并在配置中添加了要进行测试的Controller实例,以及新建的Controller Advice实例和HTTP Filter实例。当然也可以用类成员的形式创建Controller Advice和HTTPFilter实例。现在我们可以看到这种测试方法的不足了:所有Controller Advice和Filter中的逻辑都需要在setup()方法中进行配置。这是因为我们这里没有任何Spring Context可以注入Advice和Filter。 使用MockMVC测试ControllerAdvice和Filter 在测试方法getWhenNotExists()中,我们测试了id不存在的情况下,请求返回的状态码是否是HttpStatus.NOT_FOUND。如果返回值与预期一致的话,说明ControllerAdvice是能够正常工作的。 在最后的测试方法workerFilter()中,我们测试了返回结果中有没有WorkerFilter添加的请求头信息。如果返回结果的header中有添加的请求头信息,说明Filter是能够正常工作的。 也可以做个验证,注释掉setup()方法中关于ControllerAdvice和Filter的配置,然后再运行getWhenNotExists()和workerFilter()方法。可以看到测试会执行失败,因为相关的ControllerAdvice和Filter无法注入到运行环境中。 另外,在这里进行ControllerAdvice和Filter的测试多少有些不妥,因为我们的目标是测试Controller层的执行逻辑。对这二者的测试可以留到集成测试中进行。 总结 使用MockMVC Standalone模式测试对Controller层进行测试不会使用任何Spring容器,Controller层所依赖的其他服务均是mock出来的,也就是说除了Controller层的逻辑,其他相关数据都是模拟的。描述如下图: 这种测试方法的优势是: 不依赖Spring容器,启动和测试耗时较少 集中于Controller层逻辑,不受其他服务接口的影响 当然其优势也是其不足所在,我们通常不会在Controller层写入太多的业务逻辑,而是将业务逻辑写在Service层。但是因为这种测试方案中没有加载Spring容器,所以无法注入依赖的Service类,因此就无法测试到Service中实现的业务逻辑。 Spring Controller测试 – 01 概述 Spring Controller测试 – 02 Standalone MockMVC Spring Controller测试 – 03 WebContext & MockMVC Spring Controller测试 – 04 SpringBootTest & MockMVC Spring Controller测试 – 05 SpringBootTest & WebServer 其他:示例代码可在CSDN下载,地址:https://download.csdn.net/download/tianxiexingyun/11065824
[阅读更多...]-
Spring Controller层测试 – 02 Standalone MockMVC
-
Spring Controller层测试 – 01 概述
Spring Controller层(Web层或API层)的测试有多种方案。有人倾向于使用纯单元测试,有人则倾向于使用集成测试。 单元测试和集成测试 先来看一下单元测试和集成测试的概念。 单元测试 单元测试是对软件中的最小可验证单元进行检查和验证。比如对Java中的类和方法的测试。 测试原则: 尽可能保证测试用例相互独立(测试用例中不能直接调用其他类的方法,而应在测试用例中重写模拟方法); 此阶段一般由软件的开发人员来实施,用以检验所开发的代码功能是否符合自己的设计要求 单元测试的作用: 可以尽早的发现缺陷; 利于重构; 简化集成; 辅助文档; 辅助设计。 单元测试的不足: 每个测试单元至少需要3~5行代码,存在投入与产出的平衡。 集成测试 集成测试是根据集成测试计划,一边将模块或其他软件单位组合成越来越大的系统,一边运行该系统,以分析所组成的系统是否正确,各组成部分是否合拍。集成测试的策略主要有自顶向下和自底向上两种。 集成测试的作用: 目的是覆盖更多的执行路径; 发现单元之间接口的错误; 发现集成后的软件同软件需求不一致的地方。 不足在于: 关注的粒度较大,控制起来比较困难 比较来说单元测试更加重视过程,而集成测试更加重视结果。 Spring提供的Controller层测试方案 我们可以在不运行web server的情况下直接对Controller的逻辑进行测试。要执行这种测试,就需要mock服务器的行为,因此也有可能在测试中漏掉一些内容。不过无需担心,我们可以在集成测试中覆盖可能会漏掉的那部分内容。 当然也可以启动一个WebServer来执行Controller层的测试。这样就可以加载整个应用的Context,因此这种方案也可以被视为一种较重的方案。 在这里介绍三种Spring Controller层的测试方案: 在standalone模式下使用MockMVC方式; 结合SpringRunner使用MockMVC方式; 结合SpringBootTest和RestTemplate进行测试。 通常在执行单元测试的时候使用MockMVC方案,在进行集成测试的时候则建议使用RestTemplate方案。原因是使用MockMVC方式可以对Controller进行细粒度的断言,而RestTemplate则是能够使用Spring的WebApplicationContext(部分或全部)。 示例程序 为了便于说明,写了一个简单的SpringBoot Application来进行演示。 在应用中有如下几个类: WorkerController:WEB接口类; WorkerControllerAdvisor:Controller异常统一处理类,这里捕获了NonExistException并修改返回的status为404; WorkerFilter:过滤器类,在response中添加了header值X-CHOBIT-APP=chobit-header IWorkerService:服务接口类; WorkerServiceImpl:服务实现类,模拟了数据库操作。 示例代码可在CSDN下载,地址:https://download.csdn.net/download/tianxiexingyun/11065824 接下来分几篇文章来介绍几种测试方案。 Spring Controller测试 – 01 概述 Spring Controller测试 – 02 Standalone MockMVC Spring Controller测试 – 03 WebContext & MockMVC Spring Controller测试 – 04 SpringBootTest & MockMVC Spring Controller测试 – 05 SpringBootTest & WebServer
[阅读更多...]