• Spring Controller层测试 – 04 SpringBootTest & MockMVC

    这种测试方案会加载完整的SpringContext,但我们仍然不需要Web Server,需要继续通过MockMVC来模拟请求。 在测试的时候主要用到了@SpringBootTest注解。看下代码: @SpringBootTest和@AutoConfigureMockMvc 使用@SpringBootTest注解会加载整个Context。这样我们可以自动获得所有在Context中注入的Bean,以及从application.properties中加载的配置信息。 在@SpringBootTest中声明webEnvironment为WebEnvironment.MOCK(默认值就是WebEnvironment.MOCK)后,结合@AutoConfigureMockMvc注解,在测试的时候会得到一个模拟的Web/Servlet环境。 因为没有Web Server,所以就无法使用RestTemplate,也就只能继续使用MockMVC了。这次MockMVC的实例是由@AutoConfigureMockMvc注解来完成的。这归功于SpringBoot的自动化配置。 所有参与测试的对象的关系如下图: 总结 这种测试方案更倾向于集成测试。它的关注点主要在于SpringBoot不同类之间的交互。 在这个测试方案中,请求仍然是通过MockMVC模拟的。不过因为有一个完整的Context,请求处理过程中的所有逻辑都是真实的,请求返回结果也是真实的。因此测试效果和使用Web Server几乎是差不多的了。 如果还是要只测试Controller中的逻辑,也可以继续使用 @MockBean注解来mock一个IWorkerService实例来覆盖Context中已有的实例。即使使用了真正的WebServer,也可以继续使用MockBean。同样在测试中也需要继续mock数据。 概括来说,这种测试的位置稍显尴尬:如果要执行单元测试来测试WEB层的逻辑,建议优先第二种方案;如果要执行集成测试,启动一个真正的Web Server,使用RestTemplate进行测试会更彻底也更加方便。 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层测试 – 03 WebContext & MockMVC

    这种Controller层测试方案会(部分)加载Spring Application Context。不过仍然还是主要是用MockMVC来进行测试,也不需要部署WebServer。 示例代码如下: 和standalone MockMVC模式相比,这种测试方案主要有如下几点不同。 SpringRunner 这种测试是由SpringRunner来执行的。SpringRunner(部分)完成了Spring Context的初始化工作,在执行测试的时候,在日志开始的部分可以看到加载Context的内容。 MockMVC 自动化配置 使用@WebMVCTest注解可以完成MockMVC实例的自动化配置,以便于使用@Autowire注解来引用这个实例。同时,在@WebMVCTest注解中还指明了要测试的Controller类,这样Spring就会在Context中加载该Controller类及其相关的配置项。 此外,@WebMVCTest注解还会主动发现Controller类相关的Filter类和Controller Advice类并完成注入。这样,我们就不需要在setup()方法中再对其进行配置了。 使用MockBean 前面提到过这种测试方案是部分加载了Spring Context。原因就是@WebMVCTest在加载类的时候只会扫描含有@Controller,@ControllerAdvice, @JsonComponent,Filter,WebMvcConfigurer和HandlerMethodArgumentResolver这些注解或接口的类,也就是在三层模型中WEB层相关的类,而@Component注解的类则会被忽略掉。因此我们无法直接从Context获取IWorkerService实例。 因此测试中使用的WorkerService实例是通过@MockBean注解生成并注入到了Spring Context中的,并不是真正的WorkerService实例。 没有真正的服务调用 需要注意这里的返回值仍然是伪造的,在测试中也没有用到任何Web Server。 这次测试的主要关注点仍然是Controller类的内部逻辑,以及一些相关的角色如Filter和Controller Advice是如何影响Controller的返回值的。 总结 这次测试和使用MockMVC Standalone模式的主要区别在于不需要显式加载Controller相关的角色,因为这里使用到了Spring Context。参与测试的角色如下图: 如果我们创建了新的Filter、新的Controller Advice或者其他参与到WEB请求响应过程中的角色,也都会在测试中完成自动注入,不需要任何其它的配置。这和我们实际使用的场景非常类似。 这次测试可以算是向集成测试的一个小小过渡。这里我们没有做任何配置就实现了对Filter和Controller Advice的测试,如果有更多的其它角色,也可以直接集成到测试中。 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中,可以在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

    [阅读更多...]