Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
9dca7a2
Update README.md
JeffLi1993 Mar 1, 2019
f9ee57f
Update README.md
JeffLi1993 Mar 1, 2019
4deabd1
Update README.md
JeffLi1993 Mar 4, 2019
2583e9f
Update README.md
JeffLi1993 Mar 4, 2019
ad2faac
Update README.md
JeffLi1993 Mar 4, 2019
dd0f24c
Update application.properties
JeffLi1993 Mar 9, 2019
7e3e9fc
版本升级
Mar 19, 2019
bccf948
Spring Boot 集成 HBase
Mar 19, 2019
871ab7b
Update README.md
JeffLi1993 Mar 30, 2019
0beaae7
Update README.md
JeffLi1993 Mar 30, 2019
12b0dd6
Update README.md
JeffLi1993 Mar 30, 2019
c9c649f
Update README.md
JeffLi1993 Mar 31, 2019
82c407b
Update README.md
JeffLi1993 Mar 31, 2019
13a3ada
Update README.md
JeffLi1993 Apr 2, 2019
4d26dc3
Update README.md
JeffLi1993 Apr 3, 2019
d9496e6
Update README.md
JeffLi1993 Apr 3, 2019
ea8b763
优化依赖
Apr 10, 2019
e62ebc3
replace parameterMap with parameterType
Apr 10, 2019
7b80306
replace parameterMap with parameterType
Apr 10, 2019
cd6fa32
完善SpringBoot Hello World 单元测试
Apr 10, 2019
b71926b
Merge pull request #73 from strongant/master
JeffLi1993 Apr 11, 2019
a590fe4
Merge pull request #72 from developlee/master
JeffLi1993 Apr 11, 2019
95c76fa
WebFlux REST API 全局异常处理 Error Handling
Apr 11, 2019
5b902de
完善章节3单元测试
Apr 11, 2019
9bd8c91
Merge pull request #75 from strongant/master
JeffLi1993 Apr 13, 2019
6473f89
Update README.md
JeffLi1993 Apr 14, 2019
b107d49
完善章节4单元测试
Apr 15, 2019
5de6bb8
Merge pull request #76 from strongant/master
JeffLi1993 Apr 15, 2019
cbe0e43
Update README.md
JeffLi1993 Apr 15, 2019
a759a8f
Update README.md
JeffLi1993 Apr 16, 2019
d7a6496
CityHandler.deleteCity方法BUG修复
YuchangLi Apr 17, 2019
7b0b5f0
Update README.md
JeffLi1993 Apr 19, 2019
f3af92e
Merge pull request #78 from YuchangLi/master
JeffLi1993 Apr 19, 2019
fe2e348
Update README.md
JeffLi1993 Apr 20, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
完善章节3单元测试
  • Loading branch information
bwh committed Apr 11, 2019
commit 5b902de8c1d7f5fc00e5b9b06685e9f3732d835b
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,23 @@ public String getIntroduction() {
public void setIntroduction(String introduction) {
this.introduction = introduction;
}

public Book(Long id, String name, String writer, String introduction) {
this.id = id;
this.name = name;
this.writer = writer;
this.introduction = introduction;
}

public Book(Long id, String name) {
this.id = id;
this.name = name;
}

public Book(String name) {
this.name = name;
}

public Book() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,18 @@ public interface BookService {
* @param id 编号
*/
Book findById(Long id);

/**
* 查找书是否存在
* @param book
* @return
*/
boolean exists(Book book);

/**
* 根据书名获取书籍
* @param name
* @return
*/
Book findByName(String name);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,40 @@

import demo.springboot.domain.Book;
import demo.springboot.service.BookService;
import demo.springboot.web.BookController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
* Book 业务层实现
*
* <p>
* Created by bysocket on 27/09/2017.
*/
@Service
public class BookServiceImpl implements BookService {

private static final AtomicLong counter = new AtomicLong();


/**
* 使用集合模拟数据库
*/
private static List<Book> books = new ArrayList<>(
Arrays.asList(
new Book(counter.incrementAndGet(), "book")));


// 模拟数据库,存储 Book 信息
// 第五章《数据存储》会替换成 MySQL 存储
private static Map<Long, Book> BOOK_DB = new HashMap<>();
private static Map<String, Book> BOOK_DB = new HashMap<>();

@Override
public List<Book> findAll() {
Expand All @@ -29,23 +45,40 @@ public List<Book> findAll() {
@Override
public Book insertByBook(Book book) {
book.setId(BOOK_DB.size() + 1L);
BOOK_DB.put(book.getId(), book);
BOOK_DB.put(book.getId().toString(), book);
return book;
}

@Override
public Book update(Book book) {
BOOK_DB.put(book.getId(), book);
BOOK_DB.put(book.getId().toString(), book);
return book;
}

@Override
public Book delete(Long id) {
return BOOK_DB.remove(id);
return BOOK_DB.remove(id.toString());
}

@Override
public Book findById(Long id) {
return BOOK_DB.get(id);
return BOOK_DB.get(id.toString());
}

@Override
public boolean exists(Book book) {
return findByName(book.getName()) != null;
}

@Override
public Book findByName(String name) {

for (Book book : books) {
if (book.getName().equals(name)) {
return book;
}
}

return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@

import demo.springboot.domain.Book;
import demo.springboot.service.BookService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.util.UriComponentsBuilder;

import java.util.List;

Expand All @@ -16,6 +22,10 @@
@RequestMapping(value = "/book")
public class BookController {


private final Logger LOG = LoggerFactory.getLogger(BookController.class);


@Autowired
BookService bookService;

Expand Down Expand Up @@ -43,8 +53,20 @@ public Book getBook(@PathVariable Long id) {
* 通过 @RequestBody 绑定实体参数,也通过 @RequestParam 传递参数
*/
@RequestMapping(value = "/create", method = RequestMethod.POST)
public Book postBook(@RequestBody Book book) {
return bookService.insertByBook(book);
public ResponseEntity<Void> postBook(@RequestBody Book book, UriComponentsBuilder ucBuilder) {

LOG.info("creating new book: {}", book);

if (book.getName().equals("conflict")){
LOG.info("a book with name " + book.getName() + " already exists");
return new ResponseEntity<>(HttpStatus.CONFLICT);
}

bookService.insertByBook(book);

HttpHeaders headers = new HttpHeaders();
headers.setLocation(ucBuilder.path("/book/{id}").buildAndExpand(book.getId()).toUri());
return new ResponseEntity<>(headers, HttpStatus.CREATED);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
package demo.springboot.web;

import com.fasterxml.jackson.databind.ObjectMapper;
import demo.springboot.WebApplication;
import demo.springboot.domain.Book;
import demo.springboot.service.BookService;
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.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
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.setup.MockMvcBuilders;

import static org.hamcrest.Matchers.*;
import static org.hamcrest.Matchers.is;
import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;


@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = WebApplication.class)
@AutoConfigureMockMvc
@TestPropertySource(locations = "classpath:application.properties")
public class BookControllerTest {

private MockMvc mockMvc;

@Mock
private BookService bookService;

@InjectMocks
private BookController bookController;

@Before
public void init() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders
.standaloneSetup(bookController)
//.addFilters(new CORSFilter())
.build();
}


@Test
public void getBookList() throws Exception {
mockMvc.perform(get("/book")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$", hasSize(0)));

}


@Test
public void test_create_book_success() throws Exception {

Book book = createOneBook();

when(bookService.insertByBook(book)).thenReturn(book);

mockMvc.perform(
post("/book/create")
.contentType(MediaType.APPLICATION_JSON)
.content(asJsonString(book)))

.andExpect(status().isCreated())
.andExpect(header().string("location", containsString("/book/1")));
}


@Test
public void test_create_book_fail_404_not_found() throws Exception {

Book book = new Book(99L, "conflict");

when(bookService.exists(book)).thenReturn(true);

mockMvc.perform(
post("/book/create")
.contentType(MediaType.APPLICATION_JSON)
.content(asJsonString(book)))
.andExpect(status().isConflict());
}

@Test
public void test_get_book_success() throws Exception {

Book book = new Book(1L, "测试获取一本书", "strongant作者", "社区 www.spring4all.com 出版社出版");

when(bookService.findById(1L)).thenReturn(book);

mockMvc.perform(get("/book/{id}", 1L))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.id", is(1)))
.andExpect(jsonPath("$.name", is("测试获取一本书")));

verify(bookService, times(1)).findById(1L);
verifyNoMoreInteractions(bookService);
}

@Test
public void test_get_by_id_fail_null_not_found() throws Exception {
when(bookService.findById(1L)).thenReturn(null);

//TODO: 查找不到应该抛出 404 状态码, Demo 待优化
mockMvc.perform(get("/book/{id}", 1L))
.andExpect(status().isOk())
.andExpect(content().string(""));

verify(bookService, times(1)).findById(1L);
verifyNoMoreInteractions(bookService);
}

@Test
public void test_update_book_success() throws Exception {

Book book = createOneBook();

when(bookService.findById(book.getId())).thenReturn(book);
doReturn(book).when(bookService).update(book);

mockMvc.perform(
put("/book/update", book)
.contentType(MediaType.APPLICATION_JSON)
.content(asJsonString(book)))
.andExpect(status().isOk());
}

@Test
public void test_update_book_fail_not_found() throws Exception {
Book book = new Book(999L, "测试书名1");

when(bookService.findById(book.getId())).thenReturn(null);

mockMvc.perform(
put("/book/update", book)
.contentType(MediaType.APPLICATION_JSON)
.content(asJsonString(book)))
.andExpect(status().isOk())
.andExpect(content().string(""));
}

// =========================================== Delete Book ============================================

@Test
public void test_delete_book_success() throws Exception {

Book book = new Book(1L, "这本书会被删除啦");

when(bookService.findById(book.getId())).thenReturn(book);
doReturn(book).when(bookService).delete(book.getId());

mockMvc.perform(
delete("/book/delete/{id}", book.getId())
).andExpect(status().isOk());
}

@Test
public void test_delete_book_fail_404_not_found() throws Exception {
Book book = new Book(1L, "这本书会被删除啦");

when(bookService.findById(book.getId())).thenReturn(null);

mockMvc.perform(
delete("/book/delete/{id}", book.getId()))
.andExpect(status().isOk());
}


public static String asJsonString(final Object obj) {
try {
final ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(obj);
} catch (Exception e) {
throw new RuntimeException(e);
}
}

private Book createOneBook() {
Book book = new Book();
book.setId(1L);
book.setName("测试书名1");
book.setIntroduction("这是一本 www.spring4all.com 社区出版的很不错的一本书籍");
book.setWriter("strongant");
return book;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
server.port=9090
Loading