springboot单元测试

Posted xiha_zhu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springboot单元测试相关的知识,希望对你有一定的参考价值。

当单元测试代码不需要Springboot功能,可以直接编写Junit测试代码

public class JunitTest 
    
    @Test
    public void test() 
        System.out.println("Junit Test");
    

spring框架提供测试模块spring-test,用于应用程序的集成测试,在springboot中,通过spring-boot-starter-test启动器来快速开启和使用。

@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringBootTest 
    
    @Autowired
    private UserMapper userMapper;
    
    @Test
    public void test() 
        System.out.println(userMapper.get(1).getName());
    

@SpringBootTest注解是普通spring(非springboot)项目中编写测试代码使用的@ContextConfiguration注解的替代品。当运行测试类时,它会从当前测试类所在包一层层向上搜索,直到找到@SpringBootApplication或@SpringBootConfiguration注释类为止,以此来确定如何装载spring应用程序的上下文资源。也可以通过classes属性手工指定装载的主配置文件。

SpringBoot MockMvc测试

@SpringBootTest
@RunWith(SpringRunner.class)
@WebAppConfiguration
public class SpringBootWebTest 
    
    @Autowired
    private WebApplicationContext webApplicationContext;

	private MockMvc mockMvc;
    
    @Resource
    private SecurityManager securityManager;
    
    private Subject subject;
    
    private MockHttpServletRequest mockHttpServletRequest;

    private MockHttpServletResponse mockHttpServletResponse;
    
	@Before
	public void setUp() 
        /**
         * MockMvcBuilders提供两方法
         *  public static DefaultMockMvcBuilder webAppContextSetup(WebApplicationContext context) 
         *       return new DefaultMockMvcBuilder(context);
         *   
         *   public static StandaloneMockMvcBuilder standaloneSetup(Object... controllers) 
         *       return new StandaloneMockMvcBuilder(controllers);
         *   
         *
         *   通过build()方法构造MockMvc对象
         */
		// 独立安装测试
		// mockMvc = MockMvcBuilders.standaloneSetup(new UserController()).build();
		// 集成web环境测试(这种方式并不会集成真正的web环境,而是通过相应的Mock Api进行模拟测试,                
        // 无需启动服务器
		mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
        
        // 模拟登录
        mockHttpServletRequest = new MockHttpServletRequest(context.getServletContext());
        mockHttpServletResponse = new MockHttpServletResponse();
        MockHttpSession mockHttpSession = new MockHttpSession(content.getServletContext());
        mockHttpServletRequest.setSession(mockHttpSession);
        SecurityUtils.setSecurityManager(securityManager);
	
    
    // 模拟登录
    private void login(String userName, String password) 
        subject = new WebSubject.Builder(mockHttpServletRequest, mockHttpServletResponse).buildWebSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(userName, password, true);
        subject.login(token);
        ThreadContext.bind(subject);
    

    /**
      * mockMvc.perform 执行一个请求
      * MockMvcRequestBuilders.get("...") 构造一个请求
      * ResultActions.param 添加请求参数
      * ResultActions.accept 设置返回类型
      * ResultActions.andExpect 添加断言
      * ResultActions.andDo 结果处理器,MockMvcResultHandlers.print()输出整个响应结果信息
      * ResultActions.andReturn 执行完成后返回相应的结果
      */
    @Test
    public void testGet() 
        MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get("/user")
                                .param("id", "1");
        mockMvc.perform(builder)
               .andExpect(MockMvcResultMatchers.status().isOk())
               .andDo(MockMvcResultHandlers.print());
    

    @Test
    public void testUpd() throws Exception 
        User user = new User();
        user.setId(1);
        user.setName("zhu");
        user.setCId("002");
        ObjectMapper mapper = new ObjectMapper(); 
   
        mockMvc.perform(MockMvcRequestBuilders.post("/updUser")
                .content(mapper.writeValueAsString(user))
                .contentType(MediaType.APPLICATION_JSON_UTF8))
            .andDo(MockMvcResultHandlers.print());
    


Mockito测试(不依赖数据库)

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-inline</artifactId>
            <version>3.8.0</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.when;

public class UserControllerTest 

    @InjectMocks
    UserController userController;

    @Mock
    private UserServiceImpl userService;

    private MockMvc mvc;

    @Before
    public void setUp() 
        MockitoAnnotations.openMocks(this);
        mvc = MockMvcBuilders.standaloneSetup(userController).build();
    

    @Test
    public void list() throws Exception 
        mockStatic(AbcUtil.class);
        when(AbcUtil.abc(any())).thenReturn("abc");
        Assert.assertEquals(AbcUtil.abc("cccc"), "abc");

        when(userService.selectUserList(any())).thenReturn(new ArrayList<>());
        MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.get("/user/list").param("id", "1");

        // @RequestBody接收对象
        JSONObject obj = new JSONObject();
        obj.put("name", "z");
        MockHttpServletRequestBuilder requestBuilder1 = MockMvcRequestBuilders.post("/test")
                .cookie(new Cookie("cookieName","value"))
                .contentType(MediaType.APPLICATION_JSON).content(obj.toJSONString());

        // MultipartFile文件上传请求
        MockMultipartFile multipartFile = new MockMultipartFile("file", "abc", "txt", "啊".getBytes(StandardCharsets.UTF_8));
        MockHttpServletRequestBuilder requestBuilder2 = MockMvcRequestBuilders.multipart("/file/upload").file(multipartFile).param("id", "123");

        ResultActions resultActions = mvc.perform(requestBuilder);
        resultActions.andReturn().getResponse().setCharacterEncoding("utf-8");
        resultActions.andDo(MockMvcResultHandlers.print());
        resultActions.andExpect(MockMvcResultMatchers.jsonPath("$.status").value(200));


      
        MvcResult mvcResult = resultActions.andReturn();
        MockHttpServletResponse response = mvcResult.getResponse();
        // 获取状态码
        int status = response.getStatus();//500状态码  302状态码  404状态码 200状态码等
        // 获取返回 @ResponseBody json字符串 : 进行反序列化处理即可
        String contentAsString = response.getContentAsString();

        // 返回ModelAndView  获取里面的页面路径
        // 代码: model.setViewName("/index");
        ModelAndView mv = mvcResult.getModelAndView();
        String  url = mv.getViewName(); //得到/index

        // 返回ModelAndView  判断里面state参数
        // model.addObject("state", 1);
        ModelAndView mv1 = mvcResult.getModelAndView();
        Map<String, Object> map = mv1.getModel();
        Integer state = (Integer) map.get("state");

        // 返回ModelAndView  判断里面的集合/map/对象
        // PageInfo<User> list=new PageInfo<>();
        // model.addObject("AdminList", list);
        ModelAndView mv2 = mvcResult.getModelAndView();
        Map<String, Object> model = mv2.getModel();
        ((PageInfo<User>) model.get("AdminList")).getList().size();
    



java.lang.IllegalArgumentException: At least one base package must be specified

原因:包扫描没有配value值 
解决: 启动类@MapperScan("value")

java.lang.ClassNotFoundException: org.springframework.transaction.TransactionException

原因:创建schedule的时候初始化报错,找不到spring事务相关的类

解决:pom配置文件添加依赖

	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-tx</artifactId>
    </dependency>

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class...

原因:在使用Json时,fasterxml.jackson将对象转换为json报错

解决:在实体类上加注解 @JsonIgnoreProperties(value = "hibernateLazyInitializer", "handler" )   或者, 关联查询fetchType = “lazy" 改为默认eager

org.apache.ibatis.reflection.ReflectionException: There is no getter for property named '...'

原因: Mapper方法参数没加注解@Param("...")

javax.websocket.server.ServerContainer not available
原因SpringBootTest在启动的时候不会启动服务器,所以WebSocket自然会报错,这个时候需要添加选项webEnvironment,以便提供一个测试的web环境
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)

以上是关于springboot单元测试的主要内容,如果未能解决你的问题,请参考以下文章

springboot单元测试采坑记录

补习系列-springboot 单元测试之道

在SpringBoot中集成单元测试

在SpringBoot中集成单元测试

SpringBoot项目单元测试

springboot单元测试