SpringBoot测试Controller层

一、准备工作

  1、导入测试依赖

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>

2、Controller层:

@RestController("/")
public class UserController {

    @Autowired
    private UserService userService;

    @RequestMapping
    public String index(){
        return "Hello World!";
    }

    @GetMapping("/user")
    public ResponseEntity<List<User>> listUser(){
        List<User> list = new ArrayList<>();
        list.add(new User(1,"张三"));
        list.add(new User(2,"李四"));
        return new ResponseEntity(list,HttpStatus.OK);
    }

    @GetMapping("/user/{userId}")
    public ResponseEntity<User> getInfo(@PathVariable("userId") Integer userId){
        User user  = userService.findByUserId(userId);
        return new ResponseEntity(user,HttpStatus.OK);
    }

}

3、UserService实现如下:

@Service
public class UserServiceImpl implements UserService {

    @Override
    public User findByUserId(Integer userId) {
        return  new User(userId,"用户" + userId);
    }
}

二、测试

  1、创建第一个测试用例:

    在类上添加@RunWith和@SpringBootTest表示是一个可以启动容器的测试类

@RunWith(SpringRunner.class)
@SpringBootTest //告诉SpringBoot去寻找主配置类(例如使用@SpringBootApplication注解标注的类),并使用它来启动一个Spring application context;假如不想启动数据库相关的配置和类,可以在使用@SpringBootApplication注解标注的类加上exclude=datasourceautoconfiguration.class,datasourcetransactionmanagerautoconfiguration.class属性
public class UserController01Test {

    @Autowired
    private UserController userController;

    //测试@SpringBootTest是否会将@Component加载到Spring application context
    @Test
    public void testContexLoads(){
        Assert.assertThat(userController,notNullValue());
    }

}

2、Spring Test支持的一个很好的特性是应用程序上下文在测试之间缓存,因此如果在测试用例中有多个方法,或者具有相同配置的多个测试用例,它们只会产生启动应用程序一次的成本。使用@DirtiesContext注解可以清空缓存,让程序重新加载。

  将上面代码改造如下:在两个方法上都添加@DirtiesContext注解,运行整个测试类,会发现容器加载了两次。

3、启动服务器对Controller进行测试:

    这种方式是通过将TestRestTemplate注入进来,进行发送请求测试,缺点是需要启动服务器。

@RunWith(SpringRunner.class)
//SpringBootTest.WebEnvironment.RANDOM_PORT设置随机端口启动服务器(有助于避免测试环境中的冲突)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class HttpRequestTest {

    //使用@LocalServerPort将端口注入进来
    @LocalServerPort
    private int port;

    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    public void greetingShouldReturnDefaultMessage() throws Exception {
        Assert.assertThat(this.restTemplate.getForObject("http://localhost:" + port + "/",String.class),
                Matchers.containsString("Hello World"));
    }
}

4、使用@AutoConfigureMockMvc注解自动注入MockMvc:

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc //不启动服务器,使用mockMvc进行测试http请求。启动了完整的Spring应用程序上下文,但没有启动服务器
public class UserController02Test {

    @Autowired
    private MockMvc mockMvc;

    /**
     * .perform() : 执行一个MockMvcRequestBuilders的请求;MockMvcRequestBuilders有.get()、.post()、.put()、.delete()等请求。
     * .andDo() : 添加一个MockMvcResultHandlers结果处理器,可以用于打印结果输出(MockMvcResultHandlers.print())。
     * .andExpect : 添加MockMvcResultMatchers验证规则,验证执行结果是否正确。
     */
    @Test
    public void shouldReturnDefaultMessage() throws Exception {
        this.mockMvc.perform(get("/"))
                .andDo(print())
                .andExpect(status().isOk())
                .andExpect(content().string(containsString("Hello World")));
    }

}

5、使用@WebMvcTest只初始化Controller层

@RunWith(SpringRunner.class)
//使用@WebMvcTest只实例化Web层,而不是整个上下文。在具有多个Controller的应用程序中,
// 甚至可以要求仅使用一个实例化,例如@WebMvcTest(UserController.class)
@WebMvcTest(UserController.class)
public class UserController03Test {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void shouldReturnDefaultMessage() throws Exception {
        this.mockMvc.perform(get("/"))
                .andDo(print())
                .andExpect(status().isOk())
                .andExpect(content().string(containsString("Hello World")));
    }

}

上面的代码会报错,因为我们使用@WebMvcTest只初始化Controller层,但是在UserController 中注入了UserService,所以报错。我们把代码注释如下,该测试就会成功了。

但是一般的Controller成都会引用到Service吧,怎么办呢,我们可以使用mockito框架的@MockBean注解进行模拟,改造后的代码如下:

@RunWith(SpringRunner.class)
//使用@WebMvcTest只实例化Web层,而不是整个上下文。在具有多个Controller的应用程序中,
// 甚至可以要求仅使用一个实例化,例如@WebMvcTest(UserController.class)
@WebMvcTest(UserController.class)
public class UserController03Test {

    @Autowired
    private MockMvc mockMvc;

    //模拟出一个userService
    @MockBean
    private UserService userService;

    @Test
    public void greetingShouldReturnMessageFromService() throws Exception {
        //模拟userService.findByUserId(1)的行为
        when(userService.findByUserId(1)).thenReturn(new User(1,"张三"));

        String result = this.mockMvc.perform(get("/user/1"))
                .andDo(print())
                .andExpect(status().isOk())
                .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(jsonPath("$.name").value("张三"))
                .andReturn().getResponse().getContentAsString();

        System.out.println("result : " + result);
    }

}

本文转自:https://www.cnblogs.com/caofanqi/p/10836459.html?from=singlemessage

原文地址:https://www.cnblogs.com/nizuimeiabc1/p/12173948.html

时间: 2024-08-02 14:58:34

SpringBoot测试Controller层的相关文章

Junit mockito 测试Controller层方法有Pageable异常

1.问题 在使用MockMVC+Mockito模拟Service层返回的时候,当我们在Controller层中参数方法调用有Pageable对象的时候,我们会发现,我们没办法生成一个Pageable的对象,会报一个Pageable是一个接口的错误.当我们把所有的参数从Pageable接口变成Pageable的实现类PageRequest的时候,所有的方法参数都换成PageRequest,又会出现一个新的错误,且不说PageRequest不能作为参数用于hibernate的分页查询,另一方面,它没

junit基础学习之-测试controller层(2)

准备工作: eclipse本身带有junit4,可以直接build path,加入junit. 连接数据库的配置文件需要修改,之前的文件是采用properties+xml文件的形式,但是在测试的时候因为不能连接服务器,所以需要需要修改配置文件,最好是重新写一个配置文件,把需要的参数直接写出来就好了. 下面是我配置文件,重点是前面,后面就不需要了. <?xml version="1.0" encoding="UTF-8"?> <beans xmlns

Spring MVC如何测试Controller(使用springmvc mock测试)

在springmvc中一般的测试用例都是测试service层,今天我来演示下如何使用springmvc mock直接测试controller层代码. 1.什么是mock测试? mock测试就是在测试过程中,对于某些不容易构造或者不容易获取的对象,用一个虚拟的对象来创建以便测试的测试方法. 2.为什么要使用mock测试? 使用Mock Object进行测试,主要是用来模拟那些在应用中不容易构造(如HttpServletRequest必须在Servlet容器中才能构造出来)或者比较复杂的对象(如JD

SpringBoot中在除Controller层 使用Validation的方式

说明:Validation 在Controller层使用Validation应该都使用过了,以下方式可以使用 Validation 在Service层完成对dto的属性校验,避免写一堆的 if else 来处理这些逻辑,提高开发效率,代码如下: 1:DTO实体类代 @Data public class AddUserParamsDto implements Serializable { private Integer id; @NotEmpty(message = "用户名不能为空")

Junit测试Controller(MockMVC使用),传输@RequestBody数据解决办法

一.单元测试的目的 简单来说就是在我们增加或者改动一些代码以后对所有逻辑的一个检测,尤其是在我们后期修改后(不论是增加新功能,修改bug),都可以做到重新测试的工作.以减少我们在发布的时候出现更过甚至是出现之前解决了的问题再次重现. 这里主要是使用MockMvc对我们的系统的Controller进行单元测试. 对数据库的操作使用事务实现回滚,及对数据库的增删改方法结束后将会还远数据库. 二.MockMvc的使用 1.首先我们上一个例子, import org.apache.commons.log

spring controller层解决 跨域问题

前段时间,开发了一个小功能.作为后端开发,我这边写好接口之后,在Junit里模拟前端对接口测试,并没什么问题.可是在前端人员调用我接口的时候,怎么调也没有返回值. 后来知道,这是因为e前端 用 ajax 调用 后端接口 跨域不被允许.解决方法其实也很简单,只要在controller层接口函数上加上注解 @CrossOrigin(origins = "XXXXX").

controller层统一拦截进行日志处理

前言 在项目中添加统一日志时,我们往往会用到aop进行切面处理,常用在controller层添加切面,以处理请求和返回的各项参数数据. 使用切面进行日志处理 下面我们就看一个例子说明基本的使用方式: package com.ding.test.core.aspect; import javax.servlet.http.HttpServletRequest; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.

使用FormData进行Ajax请求上传文件到controller层的实现

需求背景: 页面上传一个文件到controller层,然后后台对文件进行处理.文件类型不限. 第一种:单纯的上传文件 页面功能展现: 第一步:首先需要两个jar commons-fileupload-1.3.2.jarcommons-io-2.4.jar 版本不限: pom文件中相应两个jar: [html] view plain copy print? <dependency> <groupId>commons-io</groupId> <artifactId&

代理模式——用AOP测试业务层方法的执行时间

代理模式 对代理模式的理解,通过http://www.runoob.com/design-pattern/proxy-pattern.html 对AOP的代理模式,参考https://www.cnblogs.com/xujiming/p/5737531.html 目标:测试service层每一个方法的执行时间: 代理模式的本质:将被代理对象注入给代理对象,当调用代理对象时,实际上,是在调用被注入的被代理对象 理解: 代理对象 被代理对象 代理类 被代理对象 商家 厂商 房屋中介 房东 静态代理: