Spring Boot 技术探索

Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can "just run".

6、Spring Boot使用MockMvc进行单元测试

平台环境:

名称

版本号

Mac OS X

10.14.5

JDK

1.8.0_201

Apache Maven

3.6.0

IntelliJ IDEA

2019.1 (Ultimate Edition)

Spring Boot

2.1.6.RELEASE

 

操作步骤:

1、pom.xml添加一个spring-boot-starter-web依赖

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

 

2、在src/main/java/的com.example.demo_web.Controller包下,新建一个控制器类:

package com.example.demo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class IndexController
{
    @RequestMapping("/index")
    public String indexPage(ModelMap map, String name)
    {
        map.addAttribute("welcomeText", "Welcome to CodeLabX!" + name);
        return "index";
    }
}

 

3、在src/main/resources/templates下新建index.html页面

<!DOCTYPE html>
<html lang="zh-cn" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1><span th:text="${welcomeText}"></span></h1>
</body>
</html>

 

4、在src/test/java/的com.example.demo_web包里新建一个测试类:

 

代码:

package com.example.demo;

import com.example.demo.controller.IndexController;
import org.junit.Before;
import org.junit.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;

import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;

@SpringBootTest
public class MyMockTest
{
    private MockMvc mockMvc;

    @Before
    public void setUp()
    {
        mockMvc = MockMvcBuilders.standaloneSetup(new IndexController()).build();
    }

    @Test
    public void getIndex() throws Exception
    {
        mockMvc.perform(MockMvcRequestBuilders.post("/index?name=JK")).andDo(print());
    }
}

 

代码解释:

  • mockMvc.perform执行一个请求;

  • MockMvcRequestBuilders.post("/index?name=JK")构造一个POST请求

  • .andDo添加一个结果处理器,表示要对结果做点什么事情,比如此处使用MockMvcResultHandlers.print()输出整个响应结果信息。

 

5、在上面写好的测试类MyMockTest中,右键选择Run 'MyMockTest'

查看控制台显示的结果,报错了:

 

错误分析:

  主要看这句:Circular view path [index]: would dispatch back to the current handler URL [/index] again. Check your ViewResolver setup!意思是spring说,有个view path [index]的访问,会分发回到当前的handler URL [/index]形成循环。请检查你的ViewResolver设置。但是我们这里没有做ViewResolver设置。

  查找资料得知,当没有声明ViewResolver时,spring会给你注册一个默认的ViewResolver,就是JstlView的实例, 该对象继承自InternalResoureView。JstlView用来封装JSP或者同一Web应用中的其他资源,它将model对象作为request请求的属性值暴露出来, 并将该请求通过javax.servlet.RequestDispatcher转发到指定的URL。

  Spring认为, 这个view的URL是可以用来指定同一web应用中特定资源的,是可以被RequestDispatcher转发的。也就是说,在页面渲染(render)之前,Spring会试图使用RequestDispatcher来继续转发该请求。

如下代码:

if (path.startsWith("/") ? uri.equals(path) : uri.equals(StringUtils.applyRelativePath(uri, path))) 
{
    throw new ServletException("Circular view path [" + path + "]: would dispatch back " +
                        "to the current handler URL [" + uri + "] again. Check your ViewResolver setup! " +
                        "(Hint: This may be the result of an unspecified view, due to default view name generation.)");
}

  从这段代码可以看出,如果你的view name和你的path是相同的字符串,根据Spring的转发规则,就等于让自己转发给自己,会陷入死循环。所以Spring会检查到这种情况,于是抛出Circular view path异常。

 

错误解决:

通过原因分析,造成问题有两个因素:1). 缺省转发, 2). view和path同名

那么消除这两个因素任何一个就可以解决这个问题。

 

解决办法一: 消除缺省转发

  虽然在controller中已经定义了view, 但在使用Spring Test时却仍然无效,这个不知道什么原因,也许是Spring Test的Bug, 有待探究。既然无效,那就在Test中重新定义一下view, 这样虽然麻烦点,但毕竟消除了缺省转发,所以可以解决问题。

修改代码如下:

package com.example.demo;

import com.example.demo.controller.IndexController;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockitoAnnotations;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;

@SpringBootTest
public class MyMockTest
{
    private MockMvc mockMvc;

    @Before
    public void setUp()
    {
        MockitoAnnotations.initMocks(this);
        InternalResourceViewResolver resolver = new InternalResourceViewResolver(); //在test中重新配置视图解析器
        resolver.setPrefix("/WEB_INF/classes/templates/");
        resolver.setSuffix(".html");
        mockMvc = MockMvcBuilders.standaloneSetup(new IndexController()).setViewResolvers(resolver).build();
    }

    @Test
    public void getIndex() throws Exception
    {
        mockMvc.perform(MockMvcRequestBuilders.post("/index?name=JK")).andDo(print());
    }
}

 

解决办法二: 修改view和path,让他们不同名

  这个方法最简单,建议用这种办法,比如上面的index视图, 只要我们的path不是”/index"就可以,可以改view名字(比如改成myIndex),或者修改path(比如/welcome)。

修改代码如下:

package com.example.demo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class IndexController
{
    //@RequestMapping("/index")
    @RequestMapping("/welcome")
    public String indexPage(ModelMap map, String name)
    {
        map.addAttribute("welcomeText", "Welcome to CodeLabX!" + name);
        return "index";
    }
}

 

修改测试代码如下:

package com.example.demo;

import com.example.demo.controller.IndexController;
import org.junit.Before;
import org.junit.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;

import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;

@SpringBootTest
public class MyMockTest
{
    private MockMvc mockMvc;

    @Before
    public void setUp()
    {
        mockMvc = MockMvcBuilders.standaloneSetup(new IndexController()).build();
    }

    @Test
    public void getIndex() throws Exception
    {
        mockMvc.perform(MockMvcRequestBuilders.post("/welcome?name=JK")).andDo(print());
    }
}

 

运行截图:

 

资料参考:https://www.cnblogs.com/chry/p/6240965.html

 

Bootstrap Thumbnail Second
MySQL

MySQL is the world's most popular open source database.

GO

Bootstrap Thumbnail Third
算法基础

本书介绍了什么是计算机算法,如何描述它们,以及如何来评估它们。

GO