基于Spring MVC(REST API)做单元测试(mockito)
来源:互联网 发布:windows激活密匙在哪 编辑:程序博客网 时间:2024/06/06 07:49
最近在公司用的Spring Mvc REST API框架做了一个项目,并且做了基于Spring的单元测试,今天先讲一下基于Spring框架的单元测试,测试使用的是Spring自带的test组件,再结合Mockito一起编写测试案例,以下示例会包括Controller和Service,由于Repository没有自己的逻辑,所以这里就不涉及Repository的单元测试。
首先看一下RestController的代码:
package com.dhb.springmvc.controller;import com.dhb.springmvc.entity.User;import com.dhb.springmvc.service.UserService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;/** * Created by ${denghb} on 2016/7/31. */@RestController@RequestMapping("/springmvc")public class UserController { @Autowired private UserService userService; @RequestMapping(value = "/{name}", method = RequestMethod.GET) public String sayHello(@PathVariable String name) { return name; } @RequestMapping(value = "/api/addUser", method = RequestMethod.POST) public int addUserInfo(@RequestBody User user) { int result = userService.addUser(user); return result; } @RequestMapping(value = "/api/getUser/{id}", method = RequestMethod.GET) public User getUserInfo(@PathVariable int id) { return userService.findOneUser(id); } @RequestMapping(value = "/api/registerUser", method = RequestMethod.POST) public Object registerUser(@RequestBody User user) { return userService.register(user); }}
Service的功能代码,代码也比较简单,就是调用Repository做一些增删改查的动作。
package com.dhb.springmvc.service;import com.dhb.springmvc.entity.User;import com.dhb.springmvc.repository.UserDao;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;/** * Created by ${denghb} on 2016/8/2. */@Servicepublic class UserService { @Autowired UserDao userDao; public int addUser (User user) { return userDao.addUser(user); } public User findOneUser(int id) { return userDao.findOneUser(id); } public String register(User user) { User user2 = userDao.findUserByName(user.getName()); if(user2 == null) { userDao.addUser(user); return "成功"; } else { return "失败"; } }}
下面是repository代码:
package com.dhb.springmvc.repository;import com.dhb.springmvc.entity.User;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.jdbc.core.BeanPropertyRowMapper;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.jdbc.core.RowMapper;import org.springframework.stereotype.Repository;import javax.sql.DataSource;/** * Created by ${denghb} on 2016/8/2. */@Repositorypublic class UserDao { private DataSource dataSource; private JdbcTemplate jdbcTemplate; @Autowired public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; this.jdbcTemplate = new JdbcTemplate(dataSource); } public int addUser(User user) { String name = user.getName(); String password = user.getPassword(); RowMapper<User> mapper = new BeanPropertyRowMapper<>(User.class); int result = jdbcTemplate.update("insert into user(name, password) values(?,?)",name, password); return result; } public User findOneUser(int id) { RowMapper<User> mapper = new BeanPropertyRowMapper<>(User.class); User user = jdbcTemplate.queryForObject("select id, name, password from user where id = ?", mapper, id); return user; } public User findUserByName(String name) { RowMapper<User> mapper = new BeanPropertyRowMapper<>(User.class); User user = jdbcTemplate.queryForObject("select id, name, password from user where name = ?", mapper, name); return user; }}
entity类:
package com.dhb.springmvc.entity;/** * Created by ${denghb} on 2016/8/1. *///@XmlRootElement(name = "demo")//@XmlRootElementpublic class User { int id; String name; String password; public User() { } public User(String name, String password) { this.name = name; this.password = password; } public User(int id, String name, String password) { this.id = id; this.name = name; this.password = password; } //@XmlElement public int getId() { return id; } public void setId(int id) { this.id = id; } //@XmlElement public String getName() { return name; } public void setName(String name) { this.name = name; } //@XmlElement public String getPassword() { return password; } public void setPassword(String password) { this.password = password; }}
增加一个C3P0配置:
package com.dhb.springmvc.config;import com.mchange.v2.c3p0.ComboPooledDataSource;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.PropertySource;/** * Created by ${denghb} on 2016/8/2. */@Configuration//@PropertySource(value = {"classpath:c3p0.properties"})public class C3P0DataSourceBuilder { /** * 配置数据源 * @return */ @Bean(name = "dataSource") public ComboPooledDataSource getDataSource() { try { ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/demo"); dataSource.setDriverClass("com.mysql.jdbc.Driver"); dataSource.setUser("root"); dataSource.setPassword("123456"); dataSource.setMaxPoolSize(75); return dataSource; } catch (Exception e) { return null; } }}
先看对应的RestController测试:
package com.dhb.springmvc.controller;import com.dhb.springmvc.config.DhbWebApplicationInitializer;import com.dhb.springmvc.entity.User;import com.dhb.springmvc.service.UserService;import org.junit.Before;import org.junit.Test;import org.junit.runner.RunWith;import org.mockito.InjectMocks;import org.mockito.Mock;import org.mockito.MockitoAnnotations;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 static org.junit.Assert.assertEquals;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.jsonPath;import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;/** * Created by ${denghb} on 2016/8/2. */@RunWith(SpringJUnit4ClassRunner.class)@WebAppConfiguration@ContextConfiguration(classes = {DhbWebApplicationInitializer.class})public class UserControllerTest { private MockMvc mockMvc; @Mock private UserService userService; @InjectMocks private UserController userController; @Before public void setup() { MockitoAnnotations.initMocks(this); this.mockMvc = MockMvcBuilders.standaloneSetup(userController).build(); } @Test public void testAdd() { int id = 1; String name = "邓海波"; String password = "123456"; User user = new User(); user.setId(id); user.setName(name); user.setPassword(password); when(userService.addUser(user)).thenReturn(1); int restUser = userController.addUserInfo(user); assertEquals(1, restUser); verify(userService).addUser(user); } @Test public void testGetUserInfo() throws Exception { int userId = 1; String userName = "邓海波"; String userPassword = "123456"; User user = new User(); user.setId(userId); user.setName(userName); user.setPassword(userPassword); when(userService.findOneUser(userId)).thenReturn(user); mockMvc.perform(get("/springmvc/api/getUser/{id}", userId)) .andDo(print()) .andExpect(status().isOk()) .andExpect(jsonPath("id").value(userId)) .andExpect(jsonPath("name").value(userName)) .andExpect(jsonPath("password").value(userPassword)); verify(userService).findOneUser(userId); }}
首先是Spring的几个Annotate
RunWith(SpringJUnit4ClassRunner.class): 表示使用Spring Test组件进行单元测试;
WebAppConfiguration: 使用这个Annotate会在跑单元测试的时候真实的启一个web服务,然后开始调用Controller的Rest API,待单元测试跑完之后再将web服务停掉;
ContextConfiguration: 指定Bean的配置文件信息,可以有多种方式,这个例子使用的是文件路径形式,如果有多个配置文件,可以将括号中的信息配置为一个字符串数组来表示;
然后是Mockito的Annotate
Mock: 如果该对象需要mock,则加上此Annotate;
InjectMocks: 使mock对象的使用类可以注入mock对象,在上面这个例子中,mock对象是MailService,使用了MailService的是MailController,所以在Controller加上该Annotate;
Setup方法
MockitoAnnotations.initMocks(this): 将打上Mockito标签的对象起作用,使得Mock的类被Mock,使用了Mock对象的类自动与Mock对象关联。
mockMvc: 细心的朋友应该注意到了这个对象,这个对象是Controller单元测试的关键,它的初始化也是在setup方法里面。
Test Case
首先mock了MailService的send方法,让其返回一个成功的Result对象。
mockMvc.perform: 发起一个http请求。
post(url): 表示一个post请求,url对应的是Controller中被测方法的Rest url。
param(key, value): 表示一个request parameter,方法参数是key和value。
andDo(print()): 表示打印出request和response的详细信息,便于调试。
andExpect(status().isOk()): 表示期望返回的Response Status是200。
andExpect(content().string(is(expectstring)): 表示期望返回的Response Body内容是期望的字符串。
使用print打印处理的信息类似下面显示的内容:
MockHttpServletRequest: HTTP Method = GET Request URI = /springmvc/api/getUser/1 Parameters = {} Headers = {} Handler: Type = com.dhb.springmvc.controller.UserController Method = public com.dhb.springmvc.entity.User com.dhb.springmvc.controller.UserController.getUserInfo(int) 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 = {"id":1,"name":"邓海波","password":"123456"} Forwarded URL = null Redirected URL = null Cookies = []
再来看一下service对应的测试代码:
package com.dhb.springmvc.service;import com.dhb.springmvc.config.DhbWebApplicationInitializer;import com.dhb.springmvc.entity.User;import com.dhb.springmvc.repository.UserDao;import org.junit.Before;import org.junit.Test;import org.junit.runner.RunWith;import org.mockito.InjectMocks;import org.mockito.Mock;import org.mockito.MockitoAnnotations;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import static org.hamcrest.Matchers.is;import static org.junit.Assert.assertThat;import static org.mockito.Matchers.any;import static org.mockito.Matchers.anyString;import static org.mockito.Mockito.verify;import static org.mockito.Mockito.when;/** * Created by ${denghb} on 2016/8/3. */@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes = {DhbWebApplicationInitializer.class})public class UserServiceTest { @Mock private UserDao userDao; @InjectMocks private UserService userService; @Before public void setup() { MockitoAnnotations.initMocks(this); } @Test public void testRegister() { when(userDao.findUserByName(anyString())).thenReturn(null); when(userDao.addUser(any(User.class))).thenReturn(0); assertThat(userService.register(new User("邓海波", "567890")), is("成功")); verify(userDao).findUserByName(anyString()); verify(userDao).addUser(any(User.class)); }}
Service的单元测试就比较简单了,大部分内容都在RestController里面讲过,不同的地方就是RestController是使用mockMvc对象来模拟Controler的被测方法,而在Service的单元测试中则是直接调用Service的方法。
这是pom.xml文件
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.dhb.demo</groupId> <artifactId>spring4MVCHelloWorldNoXMLDemo</artifactId> <packaging>war</packaging> <version>0.1.0-SNAPSHOT</version> <name>spring4MVCHelloWorldNoXMLDemo Maven Webapp</name> <url>http://maven.apache.org</url> <properties> <jetty.context>/</jetty.context> <jetty.http.port>9089</jetty.http.port> <jetty.https.port>9444</jetty.https.port> <jetty.stopPort>10081</jetty.stopPort> <spring.version>4.1.4.RELEASE</spring.version> </properties> <dependencies> <!-- spring --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <!-- junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!-- jackson --> <dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-mapper-asl</artifactId> <version>1.9.13</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.3.4</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.1</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- mockito --> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>1.10.19</version> <scope>test</scope> </dependency> <!-- jsonPath --> <dependency> <groupId>com.jayway.jsonpath</groupId> <artifactId>json-path</artifactId> <version>2.2.0</version> </dependency> <dependency> <groupId>com.jayway.jsonpath</groupId> <artifactId>json-path-assert</artifactId> <version>2.2.0</version> </dependency> <!--c3po--> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.7</source> <target>1.7</target> <showWarnings>true</showWarnings> </configuration> </plugin> <!--maven jetty 插件配置--> <plugin> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <version>9.2.17.v20160517</version> <configuration> <webApp> <contextPath>${jetty.context}</contextPath> </webApp> <httpConnector> <port>${jetty.http.port}</port> </httpConnector> <stopKey>jetty</stopKey> <stopPort>${jetty.stopPort}</stopPort> <!--<scanIntervalSeconds>2</scanIntervalSeconds>--> </configuration> </plugin> </plugins> <finalName>Spring4MVCHelloWorldNoXMLDemo</finalName> </build></project>
这里介绍省略了一些spring web环境的配置,可以去我前面几篇博客去看哈~
1 1
- 基于Spring MVC(REST API)做单元测试(mockito)
- 基于Spring MVC(REST API)做单元测试(mockito)
- Spring中如何使用Mockito做单元测试
- 基于Spring MVC做单元测试 —— 使用JMockit
- spring mvc 创建 rest api
- spring autowired mockito单元测试
- 在spring框架中,结合mockito打桩做单元测试
- 基于spring与mockito单元测试Mock对象注入
- Spring、junit、mockito单元测试总结
- 使用Spring MVC创建REST API
- Android Studio环境下Android单元测试(基于Robolectric+Mockito)
- JUnit + Mockito 单元测试(一)
- JUnit + Mockito 单元测试(二)
- JUnit + Mockito 单元测试(三)
- JUnit + Mockito 单元测试(一)
- JUnit + Mockito 单元测试(二)
- 第16章 使用Spring MVC创建 REST API
- 单元测试:Mockito
- 泊松曲面重建
- HDU 3308 LCIS 最长连续递增序列+数据结构+线段树+单点更新
- C#开发第一天-选择一种开发语言
- 编程是工具,计算机也是工具
- 记录导入项目操作
- 基于Spring MVC(REST API)做单元测试(mockito)
- html2image 乱码
- uva 1648 Business Center 简单数学
- 系统端口详解
- iOS显示启动页时隐藏状态栏
- Objective-C 文件处理
- js序列化ajax参数对象
- 序列图
- Ubuntu14.04安装与安装后的软件的安装