如何在Spring和Spring MVC項目中進行測試


Spring框架概述

Spring大約包含了20個模塊,這些模塊組成了核心容器(Core Container)、數據訪問/集成(Data Access/Integration)、Web、AOP(面向切面編程,Aspect Oriented Programming)、Instrumentation、消息處理(Messaging)和測試(Test),如下圖:
Spring框架概述

spring-test模塊通過JUnit和TestNG組件支持單元測試和集成測試。它提供了一致性地加載和緩存Spring上下文,也提供了用於單獨測試代碼的模擬對象(mock object)。

Spring和Spring MVC的區別

spring 是是一個開源框架,是為了解決企業應用程序開發,功能如下

  • 目的:解決企業應用開發的復雜性
  • 功能:使用基本的JavaBean代替EJB,並提供了更多的企業應用功能
  • 范圍:任何Java應用

簡單來說,Spring是一個輕量級的控制反轉(IoC)和面向切面(AOP)的容器框架。
Spring的兩大核心AOP與IOC,可以單獨用於任何應用,包括與Struts等MVC框架與Hibernate等ORM框架的集成,目前很多公司所謂的輕量級開發就是用 Spring + Struts(2)+Hibernate。

spring mvc類似於struts的一個MVC開框架,其實都是屬於spring,spring mvc需要有spring的架包作為支撐才能跑起來

測試Spring項目

開發環境:

  • jdk1.8
  • IDEA 2017
  • maven 3.5

項目結構如下:
Spring test project-structure

首先創建Maven項目,添加Spring Test支持:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>4.1.5.RELEASE</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
</dependency>

TestBean

package com.fsj.ex01;

public class TestBean {
  private String content;

  public TestBean(String content) {
    super();
    this.content = content;
  }

  public String getContent() {
    return content;
  }

  public void setContent(String content) {
    this.content = content;
  }
  
}

TestConfig

package com.fsj.ex01;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration
public class TestConfig {
  @Bean // 聲明當前方法的返回值是一個bean
  @Profile("dev")
  public TestBean devTestBean() {
    return new TestBean("from development profile");
  }

  @Bean
  @Profile("prod")
  public TestBean prodTestBean() {
    return new TestBean("from production profile");
  }

}

Main

package com.fsj.ex01;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {

  public static void main(String[] args) {
    //使用AnnotationConfigApplicationContext實例化Spring容器
    AnnotationConfigApplicationContext context =
        new AnnotationConfigApplicationContext();

    context.getEnvironment().setActiveProfiles("dev"); //激活profile
    context.register(TestConfig.class);// 注冊bean配置類。
    context.refresh(); //刷新容器

    TestBean demoBean = context.getBean(TestBean.class);

    System.out.println(demoBean.getContent());

    context.close();
  }
}

DemoBeanIntegrationTest

package com.fsj.ex01;

import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class) //表示該測試用例是運用junit4進行測試,也可以換成其他測試框架
@ContextConfiguration(classes = {TestConfig.class}) //此注解用來加載配置ApplicationContext
@ActiveProfiles("prod") //聲明活動的profile
public class DemoBeanIntegrationTests {
  @Autowired //注入bean
  private TestBean testBean;

  @Test //@Test標注在方法前,表示其是一個測試的方法 無需在其配置文件中額外設置屬性.
  public void prodBeanShouldInject(){
    String expected = "from production profile";
    String actual = testBean.getContent();
    Assert.assertEquals(expected, actual);
  }

  @Before
  public void beforeMethod(){
    System.out.println("before all tests");
  }
  @After
  public void afterMethod(){
    System.out.println("after all tests.");
  }
}

其中,RunWith注解表示JUnit將不會跑其內置的測試,而是運行所引用的類中的所有測試

http://junit.sourceforge.net/javadoc/org/junit/runner/RunWith.html

@Retention(value=RUNTIME)
@Target(value=TYPE)
@Inherited
public @interface RunWith

When a class is annotated with @RunWith or extends a class annotated with @RunWith, JUnit will invoke the class it references to run the tests in that class instead of the runner built into JUnit.

啟動Main運行項目。

啟動DemoBeanIntegrationTests測試本項目。

測試Spring MVC項目

和Spring項目類似,項目完成后,在src/test/java下編寫對應的測試用例。

不同的是,為了測試web項目,需要一些Servlet相關的模擬對象,比如:MockMVC / MockHttpServletRequest / MockHttpServletResponse / MockHttpSession等等。

TestControllerIntegration

package com.fsj.ex02;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpSession;
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;

import com.fsj.ex02.MyMvcConfig;
import com.fsj.ex02.service.DemoService;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {MyMvcConfig.class})
@WebAppConfiguration("src/main/resources") //1 此注解指定web資源的位置,默認為src/main/webapp
public class TestControllerIntegrationTests {
  private MockMvc mockMvc; //2 模擬MVC對象
  
    @Autowired
    private DemoService demoService;//3 在測試用例注入spring的bean
    
    @Autowired 
    WebApplicationContext wac; //4 注入WebApplicationContext
    
    @Autowired 
    MockHttpSession session; //5 注入模擬的http session
    
    @Autowired 
    MockHttpServletRequest request; // 模擬request
    
    @Before //7 測試開始前的初始化工作
    public void setup() {
      mockMvc =
          MockMvcBuilders.webAppContextSetup(this.wac).build(); //2
      }
  
  @Test
  public void testNormalController() throws Exception{
      String exp_str = demoService.saySomething(); // expect str
    mockMvc.perform(get("/normal")) //8 模擬GET /normal
        .andExpect(status().isOk())//9 預期返回狀態為200
        .andExpect(view().name("page"))//10 預期view的名稱
        .andExpect(forwardedUrl("/WEB-INF/classes/views/page.jsp"))//11 預期頁面轉向的真正路徑
        .andExpect(model().attribute("msg", exp_str));//12 預期model里的值
        
  }
  @Test
  public void testRestController() throws Exception{
    mockMvc.perform(get("/testRest")) //13 GET
        .andExpect(status().isOk())
         .andExpect(content().contentType("text/plain;charset=UTF-8"))//14
        .andExpect(content().string(demoService.saySomething()));//15
  }
}

完整項目在: https://github.com/shenjiefeng/spring-fortest

運行結果:
spring mvc project-structure and test-result

拾遺

使用AnnotationConfigApplicationContext實例化Spring容器

AnnotationConfigApplicationContext是在Spring 3.0中新增的。這個多功能的ApplicationContext實現即可接收@Configuration類作為輸入,也可接收普通的@Component類,及使用JSR-330元數據注解的類。

當將@Configuration類作為輸入時,@Configuration類本身被注冊為一個bean定義,並且該類中所有聲明的@Bean方法也被注冊為bean定義。

當將@Component和JSR-330類作為輸入時,它們被注冊為bean定義,並且在需要的地方使用DI元數據,比如@Autowired或@Inject。

構造器實例化跟實例化一個ClassPathXmlApplicationContext時將Spring XML文件用作輸入類似,在實例化一個AnnotationConfigApplicationContext時可以使用@Configuration類作為輸入。這就允許Spring容器完全零XML配置:

public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
    MyService myService = ctx.getBean(MyService.class);
    myService.doStuff();
}

如上所述,AnnotationConfigApplicationContext不局限於僅僅使用@Configuration類。不論什么@Component或JSR-330注解的類都能夠作為AnnotationConfigApplicationContext構造器的輸入。比如:

public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(MyServiceImpl.class, Dependency1.class, Dependency2.class);
    MyService myService = ctx.getBean(MyService.class);
    myService.doStuff();
}

參考

  1. http://blog.csdn.net/tangtong1/article/details/51326887
  2. Spring Boot 實戰
  3. Spring測試框架JUnit4.4


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM