Spring入門(十四):Spring MVC控制器的2種測試方法

做爲一名研發人員,無論你願不肯意對本身的代碼進行測試,都得認可測試對於研發質量保證的重要性,這也就是爲何每一個公司的技術部都須要質量控制部的緣由,由於越早的發現代碼的bug,成本越低,好比說,Dev環境發現bug的成本要低於QA環境,QA環境發現bug的成本要低於Prod環境,Prod環境發現bug的成本最高,這也是每一個研發人員最不肯意遇到但永遠避不掉的現實。java

雖然不能徹底避免,但咱們能夠對本身的代碼進行充分的測試,下降bug出現的概率。git

因此, 本篇博客咱們主要講解下Spring MVC控制器的2種測試方法:github

  1. 部署項目後測試
  2. 藉助JUnit和Spring Test框架測試

1. 部署項目後測試

在前2篇博客中,咱們採起的就是這種測試方式,即將項目打成war包,部署到Tomcat中,運行項目後, 藉助瀏覽器或者Postman等工具對控制器進行測試。web

若是是get請求,可使用瀏覽器或者Postman測試。spring

若是是post、put、delete等請求,可使用Postman進行測試。瀏覽器

有興趣的同窗,能夠看下以前的2篇博客:微信

Spring入門(十二):Spring MVC使用講解app

Spring入門(十三):Spring MVC經常使用註解講解框架

2. 藉助Junit和Spring Test框架測試

上面的方法雖然能夠進行測試,但每次都打包、部署、運行項目、測試,顯然很不方便,不過強大的Spring經過Spring Test框架對集成測試提供了支持,接下來咱們講解具體的使用方法。webapp

由於咱們的Spring項目是經過maven管理的,因此它的項目結構有如下4個目錄:

  1. src/main/java:項目代碼
  2. src/main/resources:項目資源
  3. src/test/java:測試代碼
  4. src/test/resources:測試資源(該目錄默認沒有生成,有須要的能夠本身新建)

也就是說,咱們能夠將咱們的測試代碼放在src/test/java目錄下,不過截止目前,咱們還並未在該目錄添加任何測試代碼。

2.1 添加依賴

在添加測試代碼前,咱們須要在pom.xml中添加以下依賴:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>4.3.18.RELEASE</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>
複製代碼

也許有的同窗會好奇,爲啥本次添加的依賴增長了<scope>test</scope>, 它有啥做用呢?

帶着這個疑問,咱們編譯下項目,發現本來編譯正常的代碼居然編譯報錯了:

報錯信息提示程序包org.junit不存在,可咱們明明添加了該依賴啊,這是爲何呢,會不會和<scope>test</scope>有關呢?

恭喜你,猜對了,確實和<scope>test</scope>有關,若是你此時將該項移除,項目編譯就不報錯了(不過建議不要移除)。

這是由於,咱們在以前添加測試代碼時,都是放在src/main/java目錄下的,如今依賴包增長了<scope>test</scope>,說明這些包的存活週期是在test週期,因此咱們能夠把以前的測試代碼移到src/test/java目錄下,以下所示:

再次編譯項目,發現編譯經過。

2.2 添加控制器

添加控制器前,新建DemoService以下所示:

package chapter05.service;

import org.springframework.stereotype.Service;

@Service
public class DemoService {
    public String saySomething() {
        return "hello";
    }
}
複製代碼

注意事項:該類添加了@Service註解。

而後,新建控制器NormalController,它裏面的方法返回jsp視圖:

package chapter05.controller;

import chapter05.service.DemoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class NormalController {
    @Autowired
    private DemoService demoService;

    @RequestMapping("/normal")
    public String testPage(Model model) {
        model.addAttribute("msg", demoService.saySomething());
        return "page";
    }
}
複製代碼

接着新建控制器MyRestController,它裏面的方法直接返回信息:

package chapter05.controller;

import chapter05.service.DemoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyRestController {
    @Autowired
    private DemoService demoService;

    @RequestMapping(value = "/testRest", produces = "text/plain;charset=UTF-8")
    public String testRest() {
        return demoService.saySomething();
    }
}
複製代碼

2.3 添加測試代碼

在src/test/java下新建包chapter05,而後在其下面新建測試類TestControllerIntegrationTests以下所示:

package chapter05;

import chapter05.config.MyMvcConfig;
import chapter05.service.DemoService;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {MyMvcConfig.class})
@WebAppConfiguration("src/main/resources")
public class TestControllerIntegrationTests {
    private MockMvc mockMvc;

    @Autowired
    private DemoService demoService;

    @Autowired
    private WebApplicationContext webApplicationContext;

    @Before
    public void setup() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).build();
    }
}
複製代碼

代碼講解:

@RunWith(SpringJUnit4ClassRunner.class)用於在JUnit環境下提供Spring Test框架的功能。

@ContextConfiguration(classes = {MyMvcConfig.class})用來加載配置ApplicationContext,其中classes屬性用來加載配置類,MyMvcConfig配置類的代碼以下所示:

package chapter05.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;

/** * Spring MVC配置 */
@Configuration
@EnableWebMvc
@ComponentScan("chapter05")
public class MyMvcConfig {
    /** * 視圖解析器配置 * * @return */
    @Bean
    public InternalResourceViewResolver viewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();

        viewResolver.setPrefix("/WEB-INF/classes/views/");
        viewResolver.setSuffix(".jsp");
        viewResolver.setViewClass(JstlView.class);

        return viewResolver;
    }
}
複製代碼

@WebAppConfiguration("src/main/resources") 用來聲明加載的ApplicationContext是一個WebApplicationContext,它的屬性指定的是Web資源的位置,默認爲src/main/webapp,這裏咱們修改爲

src/main/resources。

MockMvc用來模擬Mvc對象,它在添加了@Before註解的setup()中,經過this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).build();進行初始化賦值。

而後往測試類中添加以下測試代碼:

@Test
public void testNormalController() throws Exception {
    mockMvc.perform(get("/normal"))
            .andExpect(status().isOk())
            .andExpect(view().name("page"))
            .andExpect(forwardedUrl("/WEB-INF/classes/views/page.jsp"))
            .andExpect(model().attribute("msg", demoService.saySomething()));
}
複製代碼

代碼解釋:

perform(get("/normal"))用來模擬向/normal發起get請求,

andExpect(status().isOk())預期返回的狀態碼爲200,

andExpect(view().name("page"))預期視圖的邏輯名稱爲page,

andExpect(forwardedUrl("/WEB-INF/classes/views/page.jsp"))預期視圖的真正路徑是/WEB-INF/classes/views/page.jsp",

andExpect(model().attribute("msg", demoService.saySomething()))預期Model裏有一個msg屬性,它的值是demoService.saySomething()的返回值hello。

執行該測試方法,測試經過:

最後往測試類中添加以下測試代碼:

@Test
public void testRestController() throws Exception {
    mockMvc.perform(get("/testRest"))
            .andExpect(status().isOk())
            .andExpect(content().contentType("text/plain;charset=UTF-8"))
            .andExpect(content().string(demoService.saySomething()));
}
複製代碼

代碼解釋:

perform(get("/testRest"))用來模擬向/testRest發起get請求,

andExpect(status().isOk())預期返回的狀態碼爲200,

andExpect(content().contentType("text/plain;charset=UTF-8"))預期返回值的媒體類型爲text/plain;charset=UTF-8,

andExpect(content().string(demoService.saySomething()))預期返回值的內容爲demoService.saySomething()的返回值hello。

執行該測試方法,測試經過:

3. 源碼及參考

源碼地址:github.com/zwwhnly/spr…,歡迎下載。

Craig Walls 《Spring實戰(第4版)》

汪雲飛《Java EE開發的顛覆者:Spring Boot實戰》

最後,歡迎關注個人微信公衆號:「申城異鄉人」,全部博客會同步更新。

相關文章
相關標籤/搜索