在SpringBoot中使用MockMvc和Junit进行单元测试

Mock

在面向对象的程序设计中,模拟对象(英语:mock object)是以可控的方式模拟真实对象行为的假对象。在编程过程中,通常通过模拟一些输入数据,来验证程序是否达到预期结果。
使用Mock一般分三个步骤:
1、模拟测试类所需的外部依赖;
2、执行测试代码;
3、判断执行结果是否达到预期。

MockMvc

基于RESTFul风格的SpringMVC单元测试,可以测试完整的SpringMVC流程,即从URL请求到控制处理器,带到视图渲染都可以测试。MockMvc是由spring-test包提供,实现了对Http请求的模拟访问

MockMvcBuilder接口,提供一个唯一的build方法,用来构造MockMvc
主要有两个实现:StandaloneMockMvcBuilder和DefaultMockMvcBuilder,分别对应两种测试方式,即独立安装和集成Web环境测试(并不会集成真正的web环境,而是通过相应的Mock API进行模拟测试,无须启动服务器)。

MockMvcBuilders提供了对应的创建方法standaloneSetup方法和webAppContextSetup方法,在使用时直接调用即可。

SpringBoot中使用MockMvc

第一步:引入jar包。创建SpringBoot项目中默认引入的spring-boot-starter-test间接引入了spring-test,因此无需再额外引入jar包。

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

第二步:创建HelloWorldController类,并提供test方法作为待测试的业务接口。

package com.text.mockmvc.controller;

import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class Controller {
	
    @RequestMapping("/test")
    @GetMapping
    public String test(){
        return "hello mock mvc";
    }
    
    @RequestMapping("/delete")
    @DeleteMapping
    public void delete(){
        System.out.println("删除成功!");
    }
}

第三步:编写测试类 相关解释在代码中进行了详细注释

package com.text.mockmvc;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
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 org.springframework.web.context.WebApplicationContext;

@RunWith(SpringRunner.class)
@WebAppConfiguration
@SpringBootTest(classes = SpringTestMockmvcApplication.class)
public class SpringTestMockmvcApplicationTests {

	@Autowired
	private WebApplicationContext wac;

	private MockMvc mockMvc;

	@Before
	public void setUp() throws Exception {
		this.mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
	}

	@Test
	public void contextLoads() throws Exception {
		MvcResult mvcResult = mockMvc.perform(
				 MockMvcRequestBuilders.get("/test") // 构建get方式来调用接口
				 // MockMvcRequestBuilders.get("/delete") // 构建get方式来调用接口
				 .contentType(MediaType.APPLICATION_JSON_UTF8) // 设置请求参数的类型
				 .param("hello", "world")// 构建请求参数
		).andExpect(MockMvcResultMatchers.status().isOk())//添加ResultMatcher验证规则,验证控制器执行完成后结果是否正确
	     .andReturn();//最后返回相应的MvcResult;然后进行自定义验证/进行下一步的异步处理。
		
		System.out.println("执行后的mvcResult:------" + mvcResult.getResponse().getContentAsString());
	}
}

执行结果如下图所示:
在SpringBoot中使用MockMvc和Junit进行单元测试_第1张图片
实际项目中使用如下,由于项目是整合JWT验证,这里访问还需要进行权限的验证,所以我在.header(“Authorization”, authorization),这里进行了配置。

@Slf4j
@RestController
@RequestMapping("/api/bg")
@Api(value = "BG绩效仪表盘", tags = {"BG绩效仪表盘"})
public class BzBgPanelController {
    @Autowired
    IBzBgPanelService bzBgPanelService;
    @Autowired
    IBzCustomerPanelService bzCustomerPanelService;

    @ApiOperation("查询年度指标数据")
    @AutoLog(value = "查询年度指标数据")
    @RequestMapping(value = "/panel", method = RequestMethod.GET)
    public Result getBgYearPanelIndex(@RequestParam(name = "business_type") String businessType,@RequestParam(name = "second_product_line") String secondProductLine,@RequestParam(name = "year") String year)
    {
        Result<LinkedHashMap<String,Object>> result = new Result<>();
        LinkedHashMap<String, Object>  entitiesBack = bzBgPanelService.getBgPanelIndex(businessType,secondProductLine,year);
        if(entitiesBack==null)
            return Result.error(401,"未查询到数据");
        result.setResult(entitiesBack);
        result.success("OK");
        return result;
    }
}    
@RunWith(SpringRunner.class)
@SpringBootTest
public class BzBgPanelControllerTest {

    @Autowired
    private WebApplicationContext webApplicationContext;

    private MockMvc mockMvc;

    @Before
    public void setupMockMvc() {
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
        org.apache.shiro.mgt.SecurityManager securityManager = (org.apache.shiro.mgt.SecurityManager) webApplicationContext.getBean("securityManager");
        SecurityUtils.setSecurityManager(securityManager);
    }

    @Test
    public void getBgYearPanelIndex() throws Exception {
        MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get("/api/bg/panel")
                .header("Authorization", "************************")
                .param("business_type", "A")
                .param("second_product_line", "A01")
                .param("year", "2021")
        )
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andDo(print())
                .andReturn();
        //自定义断言
        /*int status=mvcResult.getResponse().getStatus();                 //得到返回代码
        String content=mvcResult.getResponse().getContentAsString();    //得到返回结果
        Assert.assertEquals(200,status);                        //断言,判断返回代码是否正确
        Assert.assertEquals("hello lvgang",content);            //断言,判断返回的值是否正确*/
    }
}

SpringBoot中使用Junit

前面配置不变,只需要更改测试类即可。

package com.text.mockmvc;

import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import com.text.mockmvc.controller.Controller;

@RunWith(SpringRunner.class)
//注意这里一定要是程序主类名SpringTestMockmvcApplication
@SpringBootTest(classes = SpringTestMockmvcApplication.class)
public class SpringJunitTest {
	
	@Autowired
	private Controller controller;
	
	@Test
	public void testTest() {
	    //执行控制层的test方法
		System.out.println(controller.test());
	}

	@Test
	public void  testDelete() {
	    //执行控制层的delete方法
		controller.delete();
	}
}

执行结果如下图所示:
在SpringBoot中使用MockMvc和Junit进行单元测试_第2张图片
注意:如果需要测试包含Shiro Subject的控制层方法,请参考下篇博客
MockMVC登录后测试SpringBoot项目包含Shiro Subject的控制层方法

参考资料
在SpringBoot中使用MockMvc进行单位测试
MockMvc进行单元测试
SpringBoot基础之MockMvc单元测试
mockMvc使用教程

你可能感兴趣的:(SpringBoot,单元测试,java)