Spring 基础 用mock对Controller执行测试(系列号4)
为什么需要用 mock 去测试控制类
因为用 mock 可以模拟 http 请求,这样就不用老是开启服务测试啦...
注意:在此之前需要在pom中添加mvc测试包的依赖。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
了解本次学习的文件夹结构:
可以看到,这些都是一些基本的、必要的配置和文件结构。前面用pages文件夹包含对应controller的输出 jsp 页面。
先看看我们定义的控制类:
package com.twm.bookmvc;
import com.twm.bookmvc.dto.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class HelloController {
@ResponseBody
@RequestMapping("/testJson")
public String testJson(){
return "book";
}
@RequestMapping("/hello")
public String hello() {
return "hello";
}
@Autowired
private Book book;
@RequestMapping("/book")
public String getbook(Model model){
model.addAttribute("firstbook_1",book.getMessage());
return "book";
}
}
下面就让我们模拟 http 请求去测试 controller 类的反应。
在test文件夹内最里面的APPTest.java内建立测试
package com.twm.bookmvc;
import org.junit.Test;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*;
/**
* Unit test for simple App.
*/
public class AppTest
{
@Test
public void testBookController(){
// 创建需要被测试类的实例
HelloController helloController = new HelloController();
// 搭建 mvc mock
MockMvc mockMvc = standaloneSetup(helloController).build();
try {
mockMvc.perform(get("/hello")).andExpect(view().name("hello"));
} catch (Exception e) {
e.printStackTrace();
}
}
}
这里有几点是我们需要注意的:
1. 如果请求名称 /hello 和 jsp 名称相同 比如都是 hello,后台报错:javax.servlet.ServletException: Circular view path [hello]: would dispatch back to the current handler URL [/hello]
因为:
当没有声明ViewResolver时,spring会注册一个默认的ViewResolver,就是JstlView的实例, 该对象继承自InternalResoureView。
JstlView用来封装JSP或者同一Web应用中的其他资源,它将model对象作为request请求的属性值暴露出来, 并将该请求通过javax.servlet.RequestDispatcher转发到指定的URL.
Spring认为, 这个view的URL是可以用来指定同一web应用中特定资源的,是可以被RequestDispatcher转发的。
也就是说,在页面渲染(render)之前,Spring会试图使用RequestDispatcher来继续转发该请求。(由于本项目配置的恰巧也是jsp解析器,所以就造成,请求进入控制器后,又被请求转发,再次进入控制器,无限循环...)
解决方案:补全请求转发,让其转入别名视图,跳出循环,或避免请求与页面重名。
2.当涉及到 IOC 或 AOP 时需要开启springmvc才行,无法单独测试。