diff --git a/BE/build.gradle b/BE/build.gradle index 4f5a4789e..bf81fdf91 100644 --- a/BE/build.gradle +++ b/BE/build.gradle @@ -17,13 +17,15 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-jdbc' + // lombok + implementation 'org.projectlombok:lombok' + // h2 runtimeOnly 'com.h2database:h2' // test testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'io.rest-assured:rest-assured' - } tasks.named('test') { diff --git a/BE/src/main/java/codesquad/be/todoserver/config/WebConfig.java b/BE/src/main/java/codesquad/be/todoserver/config/WebConfig.java new file mode 100644 index 000000000..484c49b7f --- /dev/null +++ b/BE/src/main/java/codesquad/be/todoserver/config/WebConfig.java @@ -0,0 +1,19 @@ +package codesquad.be.todoserver.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.method.HandlerTypePredicate; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +@EnableWebMvc +public class WebConfig implements WebMvcConfigurer { + + @Override + public void configurePathMatch(PathMatchConfigurer configurer) { + configurer + .addPathPrefix("/api", + HandlerTypePredicate.forBasePackage("codesquad.be.todoserver.controller")); + } +} diff --git a/BE/src/main/java/codesquad/be/todoserver/controller/HistoryController.java b/BE/src/main/java/codesquad/be/todoserver/controller/HistoryController.java new file mode 100644 index 000000000..955542011 --- /dev/null +++ b/BE/src/main/java/codesquad/be/todoserver/controller/HistoryController.java @@ -0,0 +1,22 @@ +package codesquad.be.todoserver.controller; + +import codesquad.be.todoserver.domain.History; +import codesquad.be.todoserver.service.HistoryService; +import java.util.List; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class HistoryController { + + private final HistoryService historiesService; + + public HistoryController(HistoryService historiesService) { + this.historiesService = historiesService; + } + + @GetMapping("/histories") + public List getAllHistory() { + return historiesService.getAllHistory(); + } +} diff --git a/BE/src/main/java/codesquad/be/todoserver/controller/TodoController.java b/BE/src/main/java/codesquad/be/todoserver/controller/TodoController.java index 1fdccd297..bb07b1cc5 100644 --- a/BE/src/main/java/codesquad/be/todoserver/controller/TodoController.java +++ b/BE/src/main/java/codesquad/be/todoserver/controller/TodoController.java @@ -2,18 +2,15 @@ import codesquad.be.todoserver.domain.Todo; import codesquad.be.todoserver.service.TodoService; -import org.springframework.beans.factory.annotation.Autowired; +import java.util.List; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController -@RequestMapping("api") public class TodoController { - @Autowired - private TodoService todoService; + private final TodoService todoService; public TodoController(TodoService todoService) { this.todoService = todoService; @@ -23,4 +20,9 @@ public TodoController(TodoService todoService) { public Todo getById(@PathVariable Long id) { return todoService.getById(id); } + + @GetMapping("/todos") + public List todoList() { + return todoService.findTodos(); + } } diff --git a/BE/src/main/java/codesquad/be/todoserver/domain/History.java b/BE/src/main/java/codesquad/be/todoserver/domain/History.java new file mode 100644 index 000000000..e16967e09 --- /dev/null +++ b/BE/src/main/java/codesquad/be/todoserver/domain/History.java @@ -0,0 +1,29 @@ +package codesquad.be.todoserver.domain; + +import lombok.Getter; + +@Getter +public class History { + + private final Long id; + private final Long todoId; + private final String todoTitle; + private final String user; + private final String action; + private final String fromStatus; + private final String toStatus; + private final String createdAt; + + public History(Long id, Long todoId, String todoTitle, String user, String action, + String fromStatus, String toStatus, String createdAt) { + this.id = id; + this.todoId = todoId; + this.todoTitle = todoTitle; + this.user = user; + this.action = action; + this.fromStatus = fromStatus; + this.toStatus = toStatus; + this.createdAt = createdAt; + } + +} diff --git a/BE/src/main/java/codesquad/be/todoserver/domain/Todo.java b/BE/src/main/java/codesquad/be/todoserver/domain/Todo.java index ae08d28da..9267d7ac0 100644 --- a/BE/src/main/java/codesquad/be/todoserver/domain/Todo.java +++ b/BE/src/main/java/codesquad/be/todoserver/domain/Todo.java @@ -1,7 +1,11 @@ package codesquad.be.todoserver.domain; import java.time.LocalDateTime; +import lombok.Getter; +import lombok.Setter; +@Getter +@Setter public class Todo { private Long id; @@ -9,14 +13,14 @@ public class Todo { private final String contents; private final String user; private final String status; - private LocalDateTime createdTime; - private LocalDateTime updatedTime; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; - public Todo(Long id, String title, String contents, String userId, String status) { + public Todo(Long id, String title, String contents, String user, String status) { this.id = id; this.title = title; this.contents = contents; - this.user = userId; + this.user = user; this.status = status; } @@ -27,35 +31,4 @@ public Todo(String title, String contents, String user, String status) { this.status = status; } - public Long getId() { - return id; - } - - public String getTitle() { - return title; - } - - public String getContents() { - return contents; - } - - public String getUser() { - return user; - } - - public String getStatus() { - return status; - } - - public void setId(Long id) { - this.id = id; - } - - public void setCreatedTime(LocalDateTime createdTime) { - this.createdTime = createdTime; - } - - public void setUpdatedTime(LocalDateTime updatedTime) { - this.updatedTime = updatedTime; - } } diff --git a/BE/src/main/java/codesquad/be/todoserver/repository/HistoryJdbcRepository.java b/BE/src/main/java/codesquad/be/todoserver/repository/HistoryJdbcRepository.java new file mode 100644 index 000000000..1a172e656 --- /dev/null +++ b/BE/src/main/java/codesquad/be/todoserver/repository/HistoryJdbcRepository.java @@ -0,0 +1,41 @@ +package codesquad.be.todoserver.repository; + +import codesquad.be.todoserver.domain.History; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public class HistoryJdbcRepository implements HistoryRepository { + + private final JdbcTemplate jdbcTemplate; + + @Autowired + public HistoryJdbcRepository(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + + @Override + public List findAllHistory() { + String sql = "SELECT id, todo_id, todo_title, user, action, from_status, to_status, created_at FROM HISTORY"; + + return jdbcTemplate.query(sql, historyRowMapper()); + } + + private RowMapper historyRowMapper() { + return (rs, rowNum) -> new History( + rs.getLong("id"), + rs.getLong("todo_id"), + rs.getString("todo_title"), + rs.getString("user"), + rs.getString("action"), + rs.getString("from_status"), + rs.getString("to_status"), + rs.getString("created_at") + ); + } +} diff --git a/BE/src/main/java/codesquad/be/todoserver/repository/HistoryRepository.java b/BE/src/main/java/codesquad/be/todoserver/repository/HistoryRepository.java new file mode 100644 index 000000000..f0c61c349 --- /dev/null +++ b/BE/src/main/java/codesquad/be/todoserver/repository/HistoryRepository.java @@ -0,0 +1,11 @@ +package codesquad.be.todoserver.repository; + +import codesquad.be.todoserver.domain.History; + +import java.util.List; + +public interface HistoryRepository { + + List findAllHistory(); + +} diff --git a/BE/src/main/java/codesquad/be/todoserver/repository/TodoJdbcRepository.java b/BE/src/main/java/codesquad/be/todoserver/repository/TodoJdbcRepository.java index 6a396d68c..0c513189f 100644 --- a/BE/src/main/java/codesquad/be/todoserver/repository/TodoJdbcRepository.java +++ b/BE/src/main/java/codesquad/be/todoserver/repository/TodoJdbcRepository.java @@ -1,19 +1,17 @@ package codesquad.be.todoserver.repository; import codesquad.be.todoserver.domain.Todo; -import java.time.LocalDateTime; -import java.util.List; -import java.util.Optional; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Repository; +import java.util.List; +import java.util.Optional; + @Repository public class TodoJdbcRepository implements TodoRepository { - @Autowired - private JdbcTemplate jdbcTemplate; + private final JdbcTemplate jdbcTemplate; public TodoJdbcRepository(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; @@ -21,12 +19,19 @@ public TodoJdbcRepository(JdbcTemplate jdbcTemplate) { @Override public Optional findById(Long id) { - String sql = "SELECT id, title, contents, user, status, created_time, updated_time FROM TODO WHERE id = ?"; + String sql = "SELECT id, title, contents, user, status, created_at, updated_at FROM TODO WHERE id = ?"; List todos = jdbcTemplate.query(sql, todoRowMapper(), id); return todos.stream().findAny(); } + @Override + public List findAllTodos() { + String sql = "SELECT id, title, contents, user, status, created_at, updated_at FROM TODO"; + List todos = jdbcTemplate.query(sql, todoRowMapper()); + return todos; + } + public RowMapper todoRowMapper() { return (rs, rowNum) -> { Todo todo = new Todo( @@ -35,8 +40,8 @@ public RowMapper todoRowMapper() { rs.getString("user"), rs.getString("status")); todo.setId(rs.getLong("id")); - todo.setCreatedTime(rs.getObject("created_time", LocalDateTime.class)); - todo.setUpdatedTime(rs.getObject("updated_time", LocalDateTime.class)); + todo.setCreatedAt(rs.getTimestamp("created_at").toLocalDateTime()); + todo.setUpdatedAt(rs.getTimestamp("updated_at").toLocalDateTime()); return todo; }; } diff --git a/BE/src/main/java/codesquad/be/todoserver/repository/TodoRepository.java b/BE/src/main/java/codesquad/be/todoserver/repository/TodoRepository.java index 638ea81f4..7d73e4659 100644 --- a/BE/src/main/java/codesquad/be/todoserver/repository/TodoRepository.java +++ b/BE/src/main/java/codesquad/be/todoserver/repository/TodoRepository.java @@ -1,11 +1,15 @@ package codesquad.be.todoserver.repository; import codesquad.be.todoserver.domain.Todo; -import java.util.Optional; import org.springframework.stereotype.Repository; +import java.util.List; +import java.util.Optional; + @Repository public interface TodoRepository { Optional findById(Long id); + + List findAllTodos(); } diff --git a/BE/src/main/java/codesquad/be/todoserver/service/HistoryService.java b/BE/src/main/java/codesquad/be/todoserver/service/HistoryService.java new file mode 100644 index 000000000..7831ecd77 --- /dev/null +++ b/BE/src/main/java/codesquad/be/todoserver/service/HistoryService.java @@ -0,0 +1,28 @@ +package codesquad.be.todoserver.service; + +import codesquad.be.todoserver.domain.History; +import codesquad.be.todoserver.repository.HistoryRepository; +import java.util.List; +import java.util.NoSuchElementException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class HistoryService { + + private final HistoryRepository historyRepository; + + @Autowired + public HistoryService(HistoryRepository historyRepository) { + this.historyRepository = historyRepository; + } + + public List getAllHistory() { + List histories = historyRepository.findAllHistory(); + + if (histories.isEmpty()) { + throw new NoSuchElementException("Empty History"); + } + return histories; + } +} diff --git a/BE/src/main/java/codesquad/be/todoserver/service/TodoService.java b/BE/src/main/java/codesquad/be/todoserver/service/TodoService.java index 6195d571e..6c756e284 100644 --- a/BE/src/main/java/codesquad/be/todoserver/service/TodoService.java +++ b/BE/src/main/java/codesquad/be/todoserver/service/TodoService.java @@ -3,13 +3,13 @@ import codesquad.be.todoserver.domain.Todo; import codesquad.be.todoserver.exception.NoSuchTodoFoundException; import codesquad.be.todoserver.repository.TodoRepository; -import org.springframework.beans.factory.annotation.Autowired; +import java.util.List; +import java.util.NoSuchElementException; import org.springframework.stereotype.Service; @Service public class TodoService { - @Autowired private TodoRepository todoRepository; public TodoService(TodoRepository todoRepository) { @@ -18,6 +18,15 @@ public TodoService(TodoRepository todoRepository) { public Todo getById(Long id) { return todoRepository.findById(id) - .orElseThrow(() -> new NoSuchTodoFoundException("조회할 수 없는 Todo 입니다. id : " + id)); + .orElseThrow(() -> new NoSuchTodoFoundException("id: " + id)); + } + + public List findTodos() { + List todos = todoRepository.findAllTodos(); + + if (todos.isEmpty()) { + throw new NoSuchElementException("Empty Todos"); + } + return todos; } } diff --git a/BE/src/main/resources/application.yml b/BE/src/main/resources/application.yml index 5ed94be5b..ac75ff78f 100644 --- a/BE/src/main/resources/application.yml +++ b/BE/src/main/resources/application.yml @@ -1,7 +1,7 @@ spring: datasource: driverClassName: org.h2.Driver - url: jdbc:h2:~/todo-server + url: jdbc:h2:mem:testTodo username: sa sql: init: diff --git a/BE/src/main/resources/db/data.sql b/BE/src/main/resources/db/data.sql index 063595be0..a61294074 100644 --- a/BE/src/main/resources/db/data.sql +++ b/BE/src/main/resources/db/data.sql @@ -1,5 +1,5 @@ -INSERT INTO TODO (TITLE, CONTENTS, USER, STATUS, CREATED_TIME, UPDATED_TIME) -VALUES ('Github 공부하기', 'add, commit, push', 'sam', 'todo', '2022-04-06T15:30:00.000+09:00', +INSERT INTO TODO (TITLE, CONTENTS, USER, STATUS, CREATED_AT, UPDATED_AT) +VALUES ('Github 공부하기', 'add, commit, push', 'sam', 'doing', '2022-04-06T15:30:00.000+09:00', '2022-04-06T15:30:00.000+09:00'), ('블로그에 포스팅할 것', '*Github 공부내용 \r\n *모던 자바스크립트 1장 공부내용', 'sam', 'todo', '2022-04-07T15:30:00.000+09:00', '2022-04-07T15:30:00.000+09:00'), @@ -7,3 +7,7 @@ VALUES ('Github 공부하기', 'add, commit, push', 'sam', 'todo', '2022-04-06T1 '2022-04-07T20:30:00.000+09:00'), ('여자친구와 데이트', '초밥 먹으러 가기', 'sam', 'done', '2022-04-08T15:30:00.000+09:00', '2022-04-08T15:30:00.000+09:00'); + +INSERT INTO HISTORY (TODO_ID, TODO_TITLE, USER, ACTION, FROM_STATUS, TO_STATUS, CREATED_AT) +VALUES (1, 'Github 공부하기', 'sam', 'add', '', 'todo', '2022-04-06T15:30:00.000+09:00'), + (1, 'Github 공부하기', 'sam', 'move', 'todo', 'doing', '2022-04-06T16:30:00.000+09:00'); diff --git a/BE/src/main/resources/db/schema.sql b/BE/src/main/resources/db/schema.sql index 4ba196636..b06ed4066 100644 --- a/BE/src/main/resources/db/schema.sql +++ b/BE/src/main/resources/db/schema.sql @@ -1,12 +1,27 @@ -DROP TABLE IF EXISTS TODO; +DROP TABLE IF EXISTS TODO CASCADE; CREATE TABLE TODO ( id BIGINT NOT NULL AUTO_INCREMENT COMMENT 'Todo의 고유한 id', - title VARCHAR(255) COMMENT '제목', - contents VARCHAR(500) COMMENT '본문', - user VARCHAR(100) COMMENT 'Todo 생성한 사용자', - status VARCHAR(10) COMMENT 'Todo의 상태(todo, doing, done)', - created_time TIMESTAMP COMMENT 'Todo 생성 시간', - updated_time TIMESTAMP COMMENT 'Todo 업데이트 시간', + title VARCHAR(255) COMMENT '제목', + contents VARCHAR(500) COMMENT '본문', + user VARCHAR(100) COMMENT 'Todo 생성한 사용자', + status VARCHAR(10) COMMENT 'Todo의 상태(todo, doing, done)', + created_at TIMESTAMP COMMENT 'Todo 생성 시간', + updated_at TIMESTAMP COMMENT 'Todo 업데이트 시간', PRIMARY KEY (id) ); + +DROP TABLE IF EXISTS HISTORY; +CREATE TABLE HISTORY +( + id BIGINT NOT NULL AUTO_INCREMENT COMMENT 'History의 고유한 id', + todo_id BIGINT COMMENT '외래키 : Todo의 고유한 id', + todo_title VARCHAR(255) COMMENT 'todoId에 해당하는 title', + user VARCHAR(100) COMMENT 'Todo 생성한 사용자', + action VARCHAR(10) COMMENT 'Todo의 상태(todo, doing, done)', + from_status VARCHAR(10) COMMENT 'todo_id의 action (add, remove, update, move)', + to_status VARCHAR(10) COMMENT 'Todo의 상태(todo, doing, done)', + created_at TIMESTAMP COMMENT 'Todo 생성 시간', + PRIMARY KEY (id), + FOREIGN KEY (todo_Id) REFERENCES TODO(id) ON UPDATE NO ACTION ON DELETE NO ACTION +); diff --git a/BE/src/test/java/codesquad/be/todoserver/HistoriesApiAcceptanceTest.java b/BE/src/test/java/codesquad/be/todoserver/HistoriesApiAcceptanceTest.java new file mode 100644 index 000000000..fb718a7e4 --- /dev/null +++ b/BE/src/test/java/codesquad/be/todoserver/HistoriesApiAcceptanceTest.java @@ -0,0 +1,53 @@ +package codesquad.be.todoserver; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import codesquad.be.todoserver.service.HistoryService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +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.test.context.jdbc.Sql; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; + +@SpringBootTest +@AutoConfigureMockMvc +@DisplayName("API /api/histories 인수 테스트") +class HistoriesApiAcceptanceTest { + + @Autowired + MockMvc mockMvc; + + @Autowired + HistoryService historyService; + + @BeforeEach + @Sql({"/testDB/schema.sql", "/testDB/data.sql"}) + void setUp() { + + } + + @Test + void 전체_히스토리_조회_성공() throws Exception { + ResultActions perform = mockMvc.perform(get("/api/histories")); + + perform + .andExpect(status().isOk()) + .andExpect(jsonPath("$.[0].id").value(1)) + .andExpect(jsonPath("$.[0].todoId").value(1)) + .andExpect(jsonPath("$.[0].todoTitle").value("Github 공부하기")) + .andExpect(jsonPath("$.[0].action").value("add")) + + .andExpect(jsonPath("$.[1].id").value(2)) + .andExpect(jsonPath("$.[1].todoId").value(1)) + .andExpect(jsonPath("$.[1].todoTitle").value("Github 공부하기")) + .andExpect(jsonPath("$.[1].action").value("move")) + .andExpect(jsonPath("$.[1].fromStatus").value("todo")) + .andExpect(jsonPath("$.[1].toStatus").value("doing")); + } +} diff --git a/BE/src/test/java/codesquad/be/todoserver/TodosApiAcceptanceTest.java b/BE/src/test/java/codesquad/be/todoserver/TodosApiAcceptanceTest.java index 43e531977..cc23c6538 100644 --- a/BE/src/test/java/codesquad/be/todoserver/TodosApiAcceptanceTest.java +++ b/BE/src/test/java/codesquad/be/todoserver/TodosApiAcceptanceTest.java @@ -40,7 +40,7 @@ void setUp() { .body("title", equalTo("Github 공부하기")) .body("contents", equalTo("add, commit, push")) .body("user", equalTo("sam")) - .body("status", equalTo("todo")); + .body("status", equalTo("doing")); } @Test diff --git a/BE/src/test/java/codesquad/be/todoserver/controller/TodoControllerTest.java b/BE/src/test/java/codesquad/be/todoserver/controller/TodoControllerTest.java index 534ca264f..eb001ca88 100644 --- a/BE/src/test/java/codesquad/be/todoserver/controller/TodoControllerTest.java +++ b/BE/src/test/java/codesquad/be/todoserver/controller/TodoControllerTest.java @@ -2,17 +2,20 @@ import static org.mockito.BDDMockito.given; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import codesquad.be.todoserver.domain.Todo; import codesquad.be.todoserver.exception.NoSuchTodoFoundException; import codesquad.be.todoserver.service.TodoService; +import java.util.ArrayList; +import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.ResultActions; @@ -35,21 +38,39 @@ class TodoControllerTest { perform .andExpect(status().isOk()) - .andExpect(jsonPath("id").value(1)) - .andExpect(jsonPath("title").value("Github 공부하기")) - .andExpect(jsonPath("contents").value("add, commit, push")) - .andExpect(jsonPath("user").value("sam")) - .andExpect(jsonPath("status").value("todo")); + .andExpect(content().contentType(MediaType.APPLICATION_JSON)); } @Test void 특정_투두리스트_조회_실패() throws Exception { given(todoService.getById(4444L)) - .willThrow(new NoSuchTodoFoundException("조회할 수 없는 Todo 입니다. id : " + 4444)); + .willThrow(new NoSuchTodoFoundException("id: " + 4444)); ResultActions perform = mockMvc.perform(get("/api/todos/4444")); perform .andExpect(status().isNotFound()); } + + @Test + void 전체_투두_조회_성공() throws Exception { + List todos = createTestData(); + + given(todoService.findTodos()) + .willReturn(todos); + + ResultActions perform = mockMvc.perform(get("/api/todos")); + + perform + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)); + } + + private List createTestData() { + List todos = new ArrayList<>(); + todos.add(new Todo(1L, "Github 공부하기", "add, commit, push", "sam", "todo")); + todos.add(new Todo(2L, "블로그에 포스팅할 것", "*Github 공부내용 \n" + + " *모던 자바스크립트 1장 공부내용", "sam", "todo")); + return todos; + } } diff --git a/BE/src/test/java/codesquad/be/todoserver/repository/TodoRepositoryTest.java b/BE/src/test/java/codesquad/be/todoserver/repository/TodoRepositoryTest.java index 4be4c655d..a283d05b8 100644 --- a/BE/src/test/java/codesquad/be/todoserver/repository/TodoRepositoryTest.java +++ b/BE/src/test/java/codesquad/be/todoserver/repository/TodoRepositoryTest.java @@ -1,20 +1,24 @@ package codesquad.be.todoserver.repository; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; import codesquad.be.todoserver.domain.Todo; +import java.util.List; import java.util.Optional; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.data.jdbc.DataJdbcTest; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.test.context.jdbc.Sql; @DataJdbcTest +@Sql({"/testDB/schema.sql", "/testDB/data.sql"}) @DisplayName("API /api/todos/* 리포지토리 계층 단위 테스트") class TodoRepositoryTest { - private TodoRepository todoRepository; + private final TodoRepository todoRepository; @Autowired public TodoRepositoryTest(JdbcTemplate jdbcTemplate) { @@ -25,17 +29,26 @@ public TodoRepositoryTest(JdbcTemplate jdbcTemplate) { void 특정_투두리스트_조회_성공() { Todo todo = todoRepository.findById(1L).get(); - assertThat(todo.getId()).isEqualTo(1); - assertThat(todo.getTitle()).isEqualTo("Github 공부하기"); - assertThat(todo.getContents()).isEqualTo("add, commit, push"); - assertThat(todo.getUser()).isEqualTo("sam"); - assertThat(todo.getStatus()).isEqualTo("todo"); + assertAll( + () -> assertThat(todo.getId()).isEqualTo(1), + () -> assertThat(todo.getTitle()).isEqualTo("Github 공부하기"), + () -> assertThat(todo.getContents()).isEqualTo("add, commit, push"), + () -> assertThat(todo.getUser()).isEqualTo("sam"), + () -> assertThat(todo.getStatus()).isEqualTo("doing") + ); } @Test void 특정_투두리스트_조회_실패() { Optional todo = todoRepository.findById(4444L); - assertThat(todo.isPresent()).isFalse(); + assertThat(todo).isEmpty(); + } + + @Test + void 전체_투두리스트_조회_성공() { + List todos = todoRepository.findAllTodos(); + + assertThat(todos).hasSize(4); } } diff --git a/BE/src/test/java/codesquad/be/todoserver/service/TodoServiceTest.java b/BE/src/test/java/codesquad/be/todoserver/service/TodoServiceTest.java index 0ed8185bc..7925c4638 100644 --- a/BE/src/test/java/codesquad/be/todoserver/service/TodoServiceTest.java +++ b/BE/src/test/java/codesquad/be/todoserver/service/TodoServiceTest.java @@ -2,15 +2,20 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; import codesquad.be.todoserver.domain.Todo; import codesquad.be.todoserver.exception.NoSuchTodoFoundException; import codesquad.be.todoserver.repository.TodoRepository; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; @DisplayName("API /api/todos/* 서비스 계층 단위 테스트") class TodoServiceTest { @@ -19,26 +24,49 @@ class TodoServiceTest { private TodoService todoService = new TodoService(todoRepository); @Test - void 특정_투두리스트_조회_성공() throws Exception { + void 특정_투두리스트_조회_성공() { given(todoRepository.findById(1L)) .willReturn( - Optional.of(new Todo(1L, "Github 공부하기", "add, commit, push", "sam", "todo"))); + Optional.of(new Todo(1L,"Github 공부하기", "add, commit, push", "sam", "todo"))); Todo todo = todoService.getById(1L); - assertThat(todo.getId()).isEqualTo(1); - assertThat(todo.getTitle()).isEqualTo("Github 공부하기"); - assertThat(todo.getContents()).isEqualTo("add, commit, push"); - assertThat(todo.getUser()).isEqualTo("sam"); - assertThat(todo.getStatus()).isEqualTo("todo"); + assertAll( + () -> assertThat(todo.getId()).isEqualTo(1), + () -> assertThat(todo.getTitle()).isEqualTo("Github 공부하기"), + () -> assertThat(todo.getContents()).isEqualTo("add, commit, push"), + () -> assertThat(todo.getUser()).isEqualTo("sam"), + () -> assertThat(todo.getStatus()).isEqualTo("todo") + ); } - @Test - void 특정_투두리스트_조회_실패() throws Exception { - given(todoRepository.findById(4444L)) - .willThrow(new NoSuchTodoFoundException("조회할 수 없는 Todo 입니다. id : " + 4444)); + @ParameterizedTest + @ValueSource(longs = {4444L, 5555L}) + void 특정_투두리스트_조회_실패(Long id) { + given(todoRepository.findById(id)) + .willThrow(new NoSuchTodoFoundException("조회할 수 없는 Todo 입니다. id : " + id)); - assertThatThrownBy(() -> todoService.getById(4444L)) + assertThatThrownBy(() -> todoService.getById(id)) .isInstanceOf(NoSuchTodoFoundException.class); } + + @Test + void 전체_투두리스트_조회_성공() { + List todolist = createTestData(); + + given(todoRepository.findAllTodos()) + .willReturn(todolist); + + List todos = todoService.findTodos(); + + assertThat(todos).contains(todolist.get(0)); + assertThat(todos).contains(todolist.get(1)); + } + + private List createTestData() { + List todolist = new ArrayList<>(); + todolist.add(new Todo(1L, "Github 공부하기", "add, commit, push", "sam", "todo")); + todolist.add(new Todo(2L, "블로그에 포스팅할 것", "*Github 공부내용 \n" + " *모던 자바스크립트 1장 공부내용", "sam", "todo")); + return todolist; + } } diff --git a/BE/src/test/resources/application.yml b/BE/src/test/resources/application.yml new file mode 100644 index 000000000..24d570bfd --- /dev/null +++ b/BE/src/test/resources/application.yml @@ -0,0 +1,18 @@ +spring: + datasource: + driverClassName: org.h2.Driver + url: jdbc:h2:mem:testTodo + username: sa + sql: + init: + mode: always + schema-locations: classpath:testDB/schema.sql + data-locations: classpath:testDB/data.sql + h2: + console: + enabled: true + path: /h2-console + +logging: + level: + web: DEBUG diff --git a/BE/src/test/resources/testDB/data.sql b/BE/src/test/resources/testDB/data.sql new file mode 100644 index 000000000..a61294074 --- /dev/null +++ b/BE/src/test/resources/testDB/data.sql @@ -0,0 +1,13 @@ +INSERT INTO TODO (TITLE, CONTENTS, USER, STATUS, CREATED_AT, UPDATED_AT) +VALUES ('Github 공부하기', 'add, commit, push', 'sam', 'doing', '2022-04-06T15:30:00.000+09:00', + '2022-04-06T15:30:00.000+09:00'), + ('블로그에 포스팅할 것', '*Github 공부내용 \r\n *모던 자바스크립트 1장 공부내용', 'sam', 'todo', + '2022-04-07T15:30:00.000+09:00', '2022-04-07T15:30:00.000+09:00'), + ('HTMl/CSS 공부하기', 'input 태그 실습', 'sam', 'doing', '2022-04-07T20:30:00.000+09:00', + '2022-04-07T20:30:00.000+09:00'), + ('여자친구와 데이트', '초밥 먹으러 가기', 'sam', 'done', '2022-04-08T15:30:00.000+09:00', + '2022-04-08T15:30:00.000+09:00'); + +INSERT INTO HISTORY (TODO_ID, TODO_TITLE, USER, ACTION, FROM_STATUS, TO_STATUS, CREATED_AT) +VALUES (1, 'Github 공부하기', 'sam', 'add', '', 'todo', '2022-04-06T15:30:00.000+09:00'), + (1, 'Github 공부하기', 'sam', 'move', 'todo', 'doing', '2022-04-06T16:30:00.000+09:00'); diff --git a/BE/src/test/resources/testDB/schema.sql b/BE/src/test/resources/testDB/schema.sql new file mode 100644 index 000000000..b06ed4066 --- /dev/null +++ b/BE/src/test/resources/testDB/schema.sql @@ -0,0 +1,27 @@ +DROP TABLE IF EXISTS TODO CASCADE; +CREATE TABLE TODO +( + id BIGINT NOT NULL AUTO_INCREMENT COMMENT 'Todo의 고유한 id', + title VARCHAR(255) COMMENT '제목', + contents VARCHAR(500) COMMENT '본문', + user VARCHAR(100) COMMENT 'Todo 생성한 사용자', + status VARCHAR(10) COMMENT 'Todo의 상태(todo, doing, done)', + created_at TIMESTAMP COMMENT 'Todo 생성 시간', + updated_at TIMESTAMP COMMENT 'Todo 업데이트 시간', + PRIMARY KEY (id) +); + +DROP TABLE IF EXISTS HISTORY; +CREATE TABLE HISTORY +( + id BIGINT NOT NULL AUTO_INCREMENT COMMENT 'History의 고유한 id', + todo_id BIGINT COMMENT '외래키 : Todo의 고유한 id', + todo_title VARCHAR(255) COMMENT 'todoId에 해당하는 title', + user VARCHAR(100) COMMENT 'Todo 생성한 사용자', + action VARCHAR(10) COMMENT 'Todo의 상태(todo, doing, done)', + from_status VARCHAR(10) COMMENT 'todo_id의 action (add, remove, update, move)', + to_status VARCHAR(10) COMMENT 'Todo의 상태(todo, doing, done)', + created_at TIMESTAMP COMMENT 'Todo 생성 시간', + PRIMARY KEY (id), + FOREIGN KEY (todo_Id) REFERENCES TODO(id) ON UPDATE NO ACTION ON DELETE NO ACTION +);