mirror of
https://github.com/JeffLi1993/springboot-learning-example.git
synced 2026-03-13 21:43:45 +08:00
完善章节4单元测试
This commit is contained in:
@@ -54,7 +54,6 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.h2database</groupId>
|
<groupId>com.h2database</groupId>
|
||||||
<artifactId>h2</artifactId>
|
<artifactId>h2</artifactId>
|
||||||
<scope>runtime</scope>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- 模板引擎 Thymeleaf 依赖 -->
|
<!-- 模板引擎 Thymeleaf 依赖 -->
|
||||||
|
|||||||
@@ -1,12 +1,40 @@
|
|||||||
package spring.boot.core;
|
package spring.boot.core;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.CommandLineRunner;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import spring.boot.core.domain.User;
|
||||||
|
import spring.boot.core.domain.UserRepository;
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class ValidatingFormInputApplication {
|
public class ValidatingFormInputApplication implements CommandLineRunner {
|
||||||
|
|
||||||
|
|
||||||
|
private Logger LOG = LoggerFactory.getLogger(ValidatingFormInputApplication.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserRepository userRepository;
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(ValidatingFormInputApplication.class, args);
|
SpringApplication.run(ValidatingFormInputApplication.class, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(String... args) throws Exception {
|
||||||
|
User user1 = new User("Sergey", 24, "1994-01-01");
|
||||||
|
User user2 = new User("Ivan", 26, "1994-01-01");
|
||||||
|
User user3 = new User("Adam", 31, "1994-01-01");
|
||||||
|
LOG.info("Inserting data in DB.");
|
||||||
|
userRepository.save(user1);
|
||||||
|
userRepository.save(user2);
|
||||||
|
userRepository.save(user3);
|
||||||
|
LOG.info("User count in DB: {}", userRepository.count());
|
||||||
|
LOG.info("User with ID 1: {}", userRepository.findById(1L));
|
||||||
|
LOG.info("Deleting user with ID 2L form DB.");
|
||||||
|
userRepository.deleteById(2L);
|
||||||
|
LOG.info("User count in DB: {}", userRepository.count());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,6 +79,15 @@ public class User implements Serializable {
|
|||||||
this.birthday = birthday;
|
this.birthday = birthday;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public User(String name, Integer age, String birthday) {
|
||||||
|
this.name = name;
|
||||||
|
this.age = age;
|
||||||
|
this.birthday = birthday;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User() {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "User{" +
|
return "User{" +
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ public class UserController {
|
|||||||
/**
|
/**
|
||||||
* 处理 "/users/{id}" 的 GET 请求,用来删除 User 信息
|
* 处理 "/users/{id}" 的 GET 请求,用来删除 User 信息
|
||||||
*/
|
*/
|
||||||
@RequestMapping(value = "/delete/{id}", method = RequestMethod.GET)
|
@RequestMapping(value = "/delete/{id}", method = RequestMethod.DELETE)
|
||||||
public String deleteUser(@PathVariable Long id) {
|
public String deleteUser(@PathVariable Long id) {
|
||||||
|
|
||||||
userService.delete(id);
|
userService.delete(id);
|
||||||
|
|||||||
@@ -1,2 +1,15 @@
|
|||||||
|
## 开启 H2 数据库
|
||||||
|
spring.h2.console.enabled=true
|
||||||
|
|
||||||
|
## 配置 H2 数据库连接信息
|
||||||
|
spring.datasource.url=jdbc:h2:mem:testdb
|
||||||
|
spring.datasource.driverClassName=org.h2.Driver
|
||||||
|
spring.datasource.username=sa
|
||||||
|
spring.datasource.password=
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 是否显示 SQL 语句
|
## 是否显示 SQL 语句
|
||||||
spring.jpa.show-sql=true
|
spring.jpa.show-sql=true
|
||||||
|
hibernate.dialect=org.hibernate.dialect.H2Dialect
|
||||||
|
hibernate.hbm2ddl.auto=create
|
||||||
|
|||||||
@@ -0,0 +1,159 @@
|
|||||||
|
package spring.boot.core.web;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.mock.web.MockHttpServletResponse;
|
||||||
|
import org.springframework.test.context.TestPropertySource;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
import org.springframework.test.web.servlet.MvcResult;
|
||||||
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||||
|
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
|
||||||
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
|
import spring.boot.core.ValidatingFormInputApplication;
|
||||||
|
import spring.boot.core.domain.User;
|
||||||
|
import spring.boot.core.service.UserService;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static junit.framework.TestCase.assertNotNull;
|
||||||
|
import static junit.framework.TestCase.assertTrue;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.hamcrest.beans.HasPropertyWithValue.hasProperty;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||||
|
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = ValidatingFormInputApplication.class)
|
||||||
|
@AutoConfigureMockMvc
|
||||||
|
@TestPropertySource(locations = "classpath:application.properties")
|
||||||
|
public class UserControllerTest {
|
||||||
|
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MockMvc mockMvc;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserService userService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getUserList() throws Exception {
|
||||||
|
mockMvc.perform(get("/users"))
|
||||||
|
.andExpect(view().name("userList"))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andDo(print());
|
||||||
|
}
|
||||||
|
|
||||||
|
private User createUser() {
|
||||||
|
User user = new User();
|
||||||
|
user.setName("测试用户");
|
||||||
|
user.setAge(100);
|
||||||
|
user.setBirthday("1994-01-01");
|
||||||
|
return userService.insertByUser(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createUserForm() throws Exception {
|
||||||
|
|
||||||
|
mockMvc.perform(get("/users/create"))
|
||||||
|
.andDo(print())
|
||||||
|
.andExpect(view().name("userForm"))
|
||||||
|
.andExpect(request().attribute("action", "create"))
|
||||||
|
.andDo(print())
|
||||||
|
.andReturn();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void postUser() throws Exception {
|
||||||
|
User user = createUser();
|
||||||
|
assertNotNull(user);
|
||||||
|
|
||||||
|
MultiValueMap parameters = new LinkedMultiValueMap<String, String>();
|
||||||
|
Map<String, String> maps = objectMapper.convertValue(user, new TypeReference<Map<String, String>>() {
|
||||||
|
});
|
||||||
|
parameters.setAll(maps);
|
||||||
|
|
||||||
|
mockMvc.perform(post("/users/create").params(parameters))
|
||||||
|
.andDo(print())
|
||||||
|
.andExpect(status().is(HttpServletResponse.SC_FOUND))
|
||||||
|
.andDo(print())
|
||||||
|
.andExpect(view().name("redirect:/users/"))
|
||||||
|
.andDo(print())
|
||||||
|
.andReturn();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getUser() throws Exception {
|
||||||
|
|
||||||
|
MvcResult result= mockMvc.perform(get("/users/update/{id}/", 1))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(view().name("userForm"))
|
||||||
|
.andExpect(MockMvcResultMatchers.model().attributeExists("action"))
|
||||||
|
.andExpect(model().attribute("user", hasProperty("id", is(1L))))
|
||||||
|
.andExpect(model().attribute("user", hasProperty("name", is("Sergey"))))
|
||||||
|
.andExpect(model().attribute("user", hasProperty("age", is(24))))
|
||||||
|
.andExpect(model().attribute("user", hasProperty("birthday", is("1994-01-01"))))
|
||||||
|
.andReturn();
|
||||||
|
|
||||||
|
|
||||||
|
MockHttpServletResponse mockResponse=result.getResponse();
|
||||||
|
assertThat(mockResponse.getContentType()).isEqualTo("text/html;charset=UTF-8");
|
||||||
|
|
||||||
|
Collection<String> responseHeaders = mockResponse.getHeaderNames();
|
||||||
|
assertNotNull(responseHeaders);
|
||||||
|
assertEquals(2, responseHeaders.size());
|
||||||
|
assertEquals("Check for Content-Type header", "Accept-Language", responseHeaders.iterator().next());
|
||||||
|
String responseAsString=mockResponse.getContentAsString();
|
||||||
|
assertTrue(responseAsString.contains("用户管理"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void putUser() throws Exception {
|
||||||
|
User user = createUser();
|
||||||
|
assertNotNull(user);
|
||||||
|
|
||||||
|
MultiValueMap parameters = new LinkedMultiValueMap<String, String>();
|
||||||
|
Map<String, String> maps = objectMapper.convertValue(user, new TypeReference<Map<String, String>>() {
|
||||||
|
});
|
||||||
|
parameters.setAll(maps);
|
||||||
|
|
||||||
|
mockMvc.perform(post("/users/update").params(parameters))
|
||||||
|
.andDo(print())
|
||||||
|
.andExpect(status().is(HttpServletResponse.SC_FOUND))
|
||||||
|
.andDo(print())
|
||||||
|
.andExpect(view().name("redirect:/users/"))
|
||||||
|
.andDo(print())
|
||||||
|
.andReturn();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteUser() throws Exception {
|
||||||
|
mockMvc.perform( MockMvcRequestBuilders.delete("/users/delete/{id}", 1L) )
|
||||||
|
.andDo(print())
|
||||||
|
.andExpect(status().is(HttpServletResponse.SC_FOUND))
|
||||||
|
.andExpect(view().name("redirect:/users/"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] convertObjectToJsonBytes(Object object) throws IOException {
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
|
||||||
|
return mapper.writeValueAsBytes(object);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
## 开启 H2 数据库
|
||||||
|
spring.h2.console.enabled=true
|
||||||
|
|
||||||
|
## 配置 H2 数据库连接信息
|
||||||
|
spring.datasource.url=jdbc:h2:mem:testdb
|
||||||
|
spring.datasource.driverClassName=org.h2.Driver
|
||||||
|
spring.datasource.username=sa
|
||||||
|
spring.datasource.password=
|
||||||
|
|
||||||
|
|
||||||
|
## 是否显示 SQL 语句
|
||||||
|
spring.jpa.show-sql=true
|
||||||
|
hibernate.dialect=org.hibernate.dialect.H2Dialect
|
||||||
|
hibernate.hbm2ddl.auto=create
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
/* contentDiv */
|
||||||
|
.contentDiv {padding:20px 60px;}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 946 B |
@@ -0,0 +1,58 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<script type="text/javascript" th:src="@{https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js}"></script>
|
||||||
|
<link th:href="@{https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css}" rel="stylesheet"/>
|
||||||
|
<link th:href="@{/css/default.css}" rel="stylesheet"/>
|
||||||
|
<link rel="icon" th:href="@{/images/favicon.ico}" type="image/x-icon"/>
|
||||||
|
<meta charset="UTF-8"/>
|
||||||
|
<title>用户管理</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="contentDiv">
|
||||||
|
|
||||||
|
<h5> 《 Spring Boot 2.x 核心技术实战》第二章快速入门案例</h5>
|
||||||
|
|
||||||
|
<legend>
|
||||||
|
<strong>用户管理</strong>
|
||||||
|
</legend>
|
||||||
|
|
||||||
|
<form th:action="@{/users/{action}(action=${action})}" method="post" class="form-horizontal">
|
||||||
|
|
||||||
|
<input type="hidden" name="id" th:value="${user.id}"/>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="user_name" class="col-sm-2 control-label">名称:</label>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<input type="text" class="form-control" id="user_name" name="name" th:value="${user.name}" th:field="*{user.name}" />
|
||||||
|
</div>
|
||||||
|
<label class="col-sm-2 control-label text-danger" th:if="${#fields.hasErrors('user.name')}" th:errors="*{user.name}">姓名有误!</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="user_age" class="col-sm-2 control-label">年龄:</label>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<input type="text" class="form-control" id="user_age" name="age" th:value="${user.age}" th:field="*{user.age}" />
|
||||||
|
</div>
|
||||||
|
<label class="col-sm-2 control-label text-danger" th:if="${#fields.hasErrors('user.age')}" th:errors="*{user.age}">年龄有误!</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="user_birthday" class="col-sm-2 control-label">出生日期:</label>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<input type="date" class="form-control" id="user_birthday" name="birthday" th:value="${user.birthday}" th:field="*{user.birthday}"/>
|
||||||
|
</div>
|
||||||
|
<label class="col-sm-2 control-label text-danger" th:if="${#fields.hasErrors('user.birthday')}" th:errors="*{user.birthday}">生日有误!</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
|
<input class="btn btn-primary" type="submit" value="提交"/>
|
||||||
|
<input class="btn" type="button" value="返回" onclick="history.back()"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<script type="text/javascript" th:src="@{https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js}"></script>
|
||||||
|
<link th:href="@{https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css}" rel="stylesheet"/>
|
||||||
|
<link th:href="@{/css/default.css}" rel="stylesheet"/>
|
||||||
|
<link rel="icon" th:href="@{/images/favicon.ico}" type="image/x-icon"/>
|
||||||
|
<meta charset="UTF-8"/>
|
||||||
|
<title>用户列表</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="contentDiv">
|
||||||
|
|
||||||
|
<h5> 《 Spring Boot 2.x 核心技术实战》第二章快速入门案例</h5>
|
||||||
|
|
||||||
|
<table class="table table-hover table-condensed">
|
||||||
|
<legend>
|
||||||
|
<strong>用户列表</strong>
|
||||||
|
</legend>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>用户编号</th>
|
||||||
|
<th>名称</th>
|
||||||
|
<th>年龄</th>
|
||||||
|
<th>出生时间</th>
|
||||||
|
<th>管理</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr th:each="user : ${userList}">
|
||||||
|
<th scope="row" th:text="${user.id}"></th>
|
||||||
|
<td><a th:href="@{/users/update/{userId}(userId=${user.id})}" th:text="${user.name}"></a></td>
|
||||||
|
<td th:text="${user.age}"></td>
|
||||||
|
<td th:text="${user.birthday}"></td>
|
||||||
|
<td><a class="btn btn-danger" th:href="@{/users/delete/{userId}(userId=${user.id})}">删除</a></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div><a class="btn btn-primary" href="/users/create" role="button">创建用户</a></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user