欢迎光临
梦想从学习开始!

对Spring MVC做单元测试| 小熊测试

本文主要介绍 对Spring MVC做单元测试| 小熊测试,小熊希望对大家的学习或者工作具有一定的参考学习价值,在测试领域有所提升和发展。

  简单介绍在工作用到的对Controller进行单元测试。其实,在编写单元测试的时候还是遇到了一些问题没有解决(基于公司封装的框架,不能用最新的包 (⊙?⊙)b)。先记录下主要的代码,其他问题慢慢解决。

  所需要基本的依赖包

<dependency>

<groupId>org.mockito</groupId>

<artifactId>mockito-core</artifactId>

<version>1.10.19</version>

<scope>test</scope>

</dependency>

<dependency>

<groupId>com.jayway.jsonpath</groupId>

<artifactId>json-path-assert</artifactId>

<version>0.9.1</version>

<scope>test</scope>

</dependency>

<dependency>

<groupId>org.hamcrest</groupId>

<artifactId>hamcrest-core</artifactId>

<version>1.3</version>

<scope>test</scope>

</dependency>

<dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>4.11</version>

<scope>test</scope>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-test</artifactId>

<version>4.0.3.RELEASE</version>

<scope>test</scope>

</dependency>

  当然还需要一些基本的Spring的包,就不列出了。

  被测试的代码

  Controller类:

@RestController

@RequestMapping("/v0.1/statistics")

public class StatisticsController{

@Autowired

StatisticsService statisticsService;

@RequestMapping(value = "/diaries", method = RequestMethod.GET)

public Object getDiariesStatistics(@AuthenticationPrincipal UserInfo userInfo) {

if (userInfo == null) {

throw new BizException(HttpStatus.UNAUTHORIZED, "UNAUTHORIZED", "缺少认证");

}

UserStatistics userStatistics = statisticsService.getDiariesStatistics(userInfo.getUserId());

return entityToVO(userStatistics);

}

}

  Service类:

  @Service

  public class StatisticsService {

  @Autowired

  StatisticsRepository statisticsRepository;

  public UserStatistics getDiariesStatistics(String userId) {

  return statisticsRepository.findByUserId(userId);

  }

  }

  因为只是要对Controller进行单元测试,就不列举StatisticsRepository的代码了;另因为演示,也就不列举UserStatistics代码,可以自己替换为相关的实体。

  独立的Controller单元测试

  这种是单纯地对Controller进行单元测试。这里会对Service进行mock处理,流程不会走到Service层。

import org.junit.Before;

import org.junit.Test;

import org.mockito.InjectMocks;

import org.mockito.Mock;

import org.mockito.MockitoAnnotations;

import org.springframework.test.web.servlet.MockMvc;

import org.springframework.test.web.servlet.setup.MockMvcBuilders;

import static org.mockito.Matchers.any;

import static org.mockito.Mockito.verify;

import static org.mockito.Mockito.when;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;

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

import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

public class StatisticsControllerTestWithStandalone {

private MockMvc mockMvc;

@Mock

private StatisticsService statisticsService;

@InjectMocks

private StatisticsController statisticsController;

private UserStatistics userStatistics;

@Before

public void setUp() throws Exception {

MockitoAnnotations.initMocks(this);

this.mockMvc = MockMvcBuilders.standaloneSetup(statisticsController).build();

userStatistics = new UserStatistics();

userStatistics.setUserId("330134");

Statistics statistics = new Statistics();

statistics.setDiaryCount(10);

userStatistics.setStatistics(statistics);

}

@Test

public void testGetDiariesStatistics() throws Exception {

when(statisticsService.getDiariesStatistics(any(String.class))).thenReturn(userStatistics);

mockMvc.perform(get("/v0.1/statistics/diaries").header("Authorization", "debug userId=330134"))

.andDo(print()).andExpect(status().isOk())

.andExpect(content().contentType("application/json;charset=UTF-8"))

.andExpect(jsonPath("diaryCount").value(10));

verify(statisticsService).getDiariesStatistics(any(String.class));

}

}

  先来说明下代码:

  @Mock :mock出一个对象

  @InjectMocks :使mock对象的使用类可以注入mock对象。比如上面的例子中,我们要把StatisticsService注入到StatisticsController中,那么我们就要对StatisticsController进行InjectMocks,对StatisticsService进行mock

  MockitoAnnotations.initMocks(this) : 将打上Mockito标签的对象起作用,使得Mock的类被Mock,使用了Mock对象的类自动与Mock对象关联。

  通过 MockMvcBuilders.standaloneSetup 模拟一个Mvc测试环境,通过build得到一个MockMvc

  MockMvc :测试时经常用到核心API,具体可以看官网文档

  运行结果:

MockHttpServletRequest:

HTTP Method = GET

Request URI = /v0.1/statistics/diaries

Parameters = {}

Headers = {Authorization=[debug userId=330134]}

Handler:

Type = nd.sdp.imdiary.statistics.controller.StatisticsController

Method = public java.lang.Object nd.sdp.imdiary.statistics.controller.StatisticsController.getDiariesStatistics(com.nd.gaea.rest.security.authens.UserInfo)

Async:

Was async started = false

Async result = null

Resolved Exception:

Type = null

ModelAndView:

View name = null

View = null

Model = null

FlashMap:

MockHttpServletResponse:

Status = 200

Error message = null

Headers = {Content-Type=[application/json;charset=UTF-8]}

Content type = application/json;charset=UTF-8

Body = {"diaryCount":10,"firstDiaryDate":null,"lastDiaryDate":null,"unfinishedDate":null}

Forwarded URL = null

Redirected URL = null

Cookies = []

  细心看以上代码会发现,我参数用到是 any(String.class) 。这是因为在独立测试该Controller的时候, @AuthenticationPrincipal UserInfo userInfo 怎么也获得不到对应的值。据说这个在最新的Spring Security中有解决方案(用WithSecurityContextTestExcecutionListener),而项目用到是3.2.3版本。

  集成到Web的单元测试

  有的时候我们需要对系统进行集成单元测试,那么我们就可以做如下操作:

import org.junit.After;

import org.junit.Before;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.mockito.MockitoAnnotations;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.http.MediaType;

import org.springframework.security.core.context.SecurityContextHolder;

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 javax.servlet.Filter;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;

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

import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;

import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@ContextConfiguration(classes = {WebConfig.class, MongodbConfig.class})

@WebAppConfiguration

@RunWith(SpringJUnit4ClassRunner.class)

public class StatisticsControllerTest {

protected MockMvc mockMvc;

@Autowired

private Filter springSecurityFilterChain;

@Autowired

private WebApplicationContext wac;

@Before

public void setUp() {

MockitoAnnotations.initMocks(this);

this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).addFilters(springSecurityFilterChain).build();

}

@After

public void teardown() throws Exception {

SecurityContextHolder.clearContext();

}

@Test

public void testGetDiariesStatistics() throws Exception {

mockMvc.perform(get("/v0.1/statistics/diaries").header("Authorization", "debug userId=330134"))

.andDo(print()).andExpect(status().isOk())

.andExpect(content().contentType(MediaType.APPLICATION_JSON));

}

}

  以上的代码和单独的单元测试代码还是有一些不一样的。首先是多个几个类上的注解,然后就是少了对Service的mock,最后就是生成mockmvc的方式不一样了。

  @ContextConfiguration() :指定Bean的配置文件信息。项目中用的是注解风格配置,WebConfig.class等。如果你用的是xml配置,可以把它替换为对应的xml配置

  @WebAppConfiguration :在运行单元测试的时候会启动一个Web服务,所有的测试用例跑完以后停掉

  @RunWith(SpringJUnit4ClassRunner.class) :示使用Spring Test组件进行单元测试

  @Autowired WebApplicationContext wac :注入web环境的ApplicationContext容器

  MockMvcBuilders.webAppContextSetup(this.wac) :模拟真实的Spring MVC环境

  @Autowired Filter springSecurityFilterChain :获得SecurityContextPersistenceFilter

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小熊分享邦(www.xxfxb.com),希望大家能坚持软件测试之路,谢谢。

赞(0) 打赏
未经允许不得转载:小熊分享邦 » 对Spring MVC做单元测试| 小熊测试

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏