From 6e3cb1729d182acfbb10765768d2557f21ef3f24 Mon Sep 17 00:00:00 2001 From: Beenie93 Date: Fri, 19 Nov 2021 22:56:23 +0900 Subject: [PATCH 01/14] =?UTF-8?q?chore=20:=20JPA=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Beenie93 --- src/main/resources/application.yml | 11 +++++++++ src/main/resources/data.sql | 38 ++---------------------------- 2 files changed, 13 insertions(+), 36 deletions(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 067a3e0..100fa7c 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -7,3 +7,14 @@ spring: h2: console: enabled: true + jpa: + open-in-view: false + hibernate: + ddl-auto: create + properties: + hibernate: + default_batch_fetch_size: 100 + format_sql: true + show_sql: true + defer-datasource-initialization: true + diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index 7713d51..77e0c96 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -1,39 +1,5 @@ -drop table if exists user; -create table user -( - id bigint not null auto_increment primary key, - email varchar(255), - password varchar(255), - name varchar(255), - constraint user_email_constraint unique (email) -); - -drop table if exists document; -create table document -( - id bigint not null auto_increment primary key, - title varchar(255) not null, - category varchar(255) not null, - contents varchar(255) not null, - drafter_id bigint not null, - approval_state varchar(255) not null, - foreign key (drafter_id) references user (id) -); - -drop table if exists documentApproval; -create table document_approval -( - approver_id bigint not null, - document_id bigint not null, - approval_state varchar(255) not null, - approval_order tinyint not null, - approval_comment varchar(255), - foreign key (approver_id) references user (id), - foreign key (document_id) references document (id) -); - -insert into user(id, email, password, name) +insert into user(user_id, email, password, name) values (1, 'wbluke@gmail.com', '1234', '박우빈'); -insert into user(id, email, password, name) +insert into user(user_id, email, password, name) values (2, 'wbluke2@gmail.com', '1234', '닉우빈'); From 8171cb62ae26bea90362ac11236206ad4649fde8 Mon Sep 17 00:00:00 2001 From: Beenie93 Date: Fri, 19 Nov 2021 23:02:43 +0900 Subject: [PATCH 02/14] =?UTF-8?q?refactor=20:=20=ED=9A=8C=EC=9B=90=20?= =?UTF-8?q?=EB=8F=84=EB=A9=94=EC=9D=B8=20JPA=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Beenie93 --- .../controller/user/UserController.java | 2 +- .../java/playground/domain/user/User.java | 48 +++++----- .../repository/user/UserRepository.java | 66 +------------ .../playground/service/user/UserService.java | 25 +++-- .../user/request/CreateUserRequest.java | 2 +- .../controller/user/UserControllerTest.java | 2 +- .../repository/user/UserRepositoryTest.java | 94 ------------------- .../service/user/UserServiceTest.java | 5 +- 8 files changed, 51 insertions(+), 193 deletions(-) rename src/main/java/playground/{controller => service}/user/request/CreateUserRequest.java (94%) delete mode 100644 src/test/java/playground/repository/user/UserRepositoryTest.java diff --git a/src/main/java/playground/controller/user/UserController.java b/src/main/java/playground/controller/user/UserController.java index e6685f1..9a130db 100644 --- a/src/main/java/playground/controller/user/UserController.java +++ b/src/main/java/playground/controller/user/UserController.java @@ -6,8 +6,8 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import playground.controller.user.request.CreateUserRequest; import playground.service.user.UserService; +import playground.service.user.request.CreateUserRequest; import javax.validation.Valid; diff --git a/src/main/java/playground/domain/user/User.java b/src/main/java/playground/domain/user/User.java index 731d2e7..5cbe1b6 100644 --- a/src/main/java/playground/domain/user/User.java +++ b/src/main/java/playground/domain/user/User.java @@ -1,16 +1,39 @@ package playground.domain.user; -import lombok.Builder; +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; import lombok.Getter; +import lombok.NoArgsConstructor; -import java.util.Objects; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.UniqueConstraint; +@Entity @Getter +@EqualsAndHashCode(of = "id") +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(name = "user", uniqueConstraints = { + @UniqueConstraint(name = "user_email_constraint", columnNames = "email") +}) public class User { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "user_id") private Long id; + + @Column(name = "email", nullable = false) private String email; + + @Column(name = "password", nullable = false) private String password; + + @Column(name = "name", nullable = false) private String name; public User(final String email, final String password, final String name) { @@ -18,26 +41,5 @@ public User(final String email, final String password, final String name) { this.password = password; this.name = name; } - - @Builder(builderMethodName = "builderForDao") - public User(final Long id, final String email, final String password, final String name) { - this.id = id; - this.email = email; - this.password = password; - this.name = name; - } - - @Override - public boolean equals(final Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - final User user = (User) o; - return Objects.equals(id, user.id); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } } diff --git a/src/main/java/playground/repository/user/UserRepository.java b/src/main/java/playground/repository/user/UserRepository.java index 05d9895..68a1249 100644 --- a/src/main/java/playground/repository/user/UserRepository.java +++ b/src/main/java/playground/repository/user/UserRepository.java @@ -1,69 +1,7 @@ package playground.repository.user; -import org.springframework.dao.EmptyResultDataAccessException; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.support.GeneratedKeyHolder; -import org.springframework.jdbc.support.KeyHolder; -import org.springframework.stereotype.Component; +import org.springframework.data.jpa.repository.JpaRepository; import playground.domain.user.User; -import javax.sql.DataSource; -import java.sql.PreparedStatement; -import java.sql.Statement; -import java.util.Collections; -import java.util.List; - -@Component -public class UserRepository { - - private JdbcTemplate jdbcTemplate; - - public UserRepository(final DataSource dataSource) { - this.jdbcTemplate = new JdbcTemplate(dataSource); - } - - public Long save(final User user) { - String saveQuery = "insert into user (email, password, name) values (?, ?, ?)"; - KeyHolder keyHolder = new GeneratedKeyHolder(); - - jdbcTemplate.update(connection -> { - PreparedStatement ps = connection - .prepareStatement(saveQuery, Statement.RETURN_GENERATED_KEYS); - ps.setString(1, user.getEmail()); - ps.setString(2, user.getPassword()); - ps.setString(3, user.getName()); - return ps; - }, keyHolder); - - return keyHolder.getKey().longValue(); - } - - public List findAllById(final List userIds) { - String inSql = String.join(",", Collections.nCopies(userIds.size(), "?")); - String selectQuery = String.format("select * from user where id in (%s)", inSql); - - return jdbcTemplate.query(selectQuery, (rs, rowNum) -> - User.builderForDao() - .id(rs.getLong("id")) - .email(rs.getString("email")) - .password(rs.getString("password")) - .name(rs.getString("name")) - .build(), userIds.toArray()); - } - - public User findById(final Long userId) { - String selectQuery = "select * from user where id = ?"; - try { - return jdbcTemplate.queryForObject(selectQuery, (rs, rowNum) -> - User.builderForDao() - .id(rs.getLong("id")) - .email(rs.getString("email")) - .password(rs.getString("password")) - .name(rs.getString("name")) - .build(), userId); - - } catch (EmptyResultDataAccessException e) { - throw new IllegalArgumentException(String.format("[%d] 번호에 해당하는 회원이 존재하지 않습니다.", userId)); - } - } +public interface UserRepository extends JpaRepository { } diff --git a/src/main/java/playground/service/user/UserService.java b/src/main/java/playground/service/user/UserService.java index b32ce3b..eeee95d 100644 --- a/src/main/java/playground/service/user/UserService.java +++ b/src/main/java/playground/service/user/UserService.java @@ -1,12 +1,13 @@ package playground.service.user; -import org.springframework.dao.DuplicateKeyException; +import org.springframework.dao.DataIntegrityViolationException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import playground.controller.user.request.CreateUserRequest; import playground.domain.user.User; import playground.repository.user.UserRepository; +import playground.service.user.request.CreateUserRequest; +import javax.persistence.EntityNotFoundException; import java.util.List; @Service @@ -21,24 +22,34 @@ public UserService(final UserRepository userRepository) { @Transactional public void save(final CreateUserRequest createUserRequest) { User user = createUserRequest.toUser(); - saveInDatabase(user); + save(user); } - private void saveInDatabase(final User user) { + private void save(final User user) { try { userRepository.save(user); - } catch (DuplicateKeyException e) { + } catch (DataIntegrityViolationException e) { throw new IllegalArgumentException(String.format("[%s] 이미 가입된 이메일입니다.", user.getEmail())); } } @Transactional(readOnly = true) public List findAllById(final List userIds) { - return userRepository.findAllById(userIds); + List users = userRepository.findAllById(userIds); + checkEmpty(userIds, users); + + return users; + } + + private void checkEmpty(final List userIds, final List users) { + if (users.isEmpty()) { + throw new EntityNotFoundException(String.format("%s 식별번호에 해당하는 회원이 존재하지 않습니다.", userIds)); + } } @Transactional(readOnly = true) public User findById(final Long userId) { - return userRepository.findById(userId); + return userRepository.findById(userId) + .orElseThrow(() -> new EntityNotFoundException(String.format("[%d] 식별번호에 해당하는 회원이 존재하지 않습니다.", userId))); } } diff --git a/src/main/java/playground/controller/user/request/CreateUserRequest.java b/src/main/java/playground/service/user/request/CreateUserRequest.java similarity index 94% rename from src/main/java/playground/controller/user/request/CreateUserRequest.java rename to src/main/java/playground/service/user/request/CreateUserRequest.java index ed794eb..1900ed7 100644 --- a/src/main/java/playground/controller/user/request/CreateUserRequest.java +++ b/src/main/java/playground/service/user/request/CreateUserRequest.java @@ -1,4 +1,4 @@ -package playground.controller.user.request; +package playground.service.user.request; import lombok.AccessLevel; import lombok.Getter; diff --git a/src/test/java/playground/controller/user/UserControllerTest.java b/src/test/java/playground/controller/user/UserControllerTest.java index f0657d9..59892dc 100644 --- a/src/test/java/playground/controller/user/UserControllerTest.java +++ b/src/test/java/playground/controller/user/UserControllerTest.java @@ -8,8 +8,8 @@ import org.mockito.Mock; import org.springframework.http.MediaType; import playground.common.AbstractControllerTest; -import playground.controller.user.request.CreateUserRequest; import playground.service.user.UserService; +import playground.service.user.request.CreateUserRequest; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; diff --git a/src/test/java/playground/repository/user/UserRepositoryTest.java b/src/test/java/playground/repository/user/UserRepositoryTest.java deleted file mode 100644 index 98690c4..0000000 --- a/src/test/java/playground/repository/user/UserRepositoryTest.java +++ /dev/null @@ -1,94 +0,0 @@ -package playground.repository.user; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.dao.DuplicateKeyException; -import org.springframework.transaction.annotation.Transactional; -import playground.domain.user.User; - -import java.util.Arrays; -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -@SpringBootTest -@Transactional -class UserRepositoryTest { - - @Autowired - private UserRepository userRepository; - - @Test - @DisplayName("회원을 저장한다.") - void save() { - //given - User user = new User("a@naver.com", "password", "김성빈"); - - //when - long userId = userRepository.save(user); - - //then - assertThat(userId).isNotZero(); - } - - @Test - @DisplayName("중복된 이메일일 경우, 예외가 발생한다.") - void save_fail_duplicated_email() { - //given - User user1 = new User("a@naver.com", "password", "김성빈"); - userRepository.save(user1); - User user2 = new User("a@naver.com", "password2", "김성빈2"); - - //when, then - assertThatThrownBy(() -> userRepository.save(user2)) - .isInstanceOf(DuplicateKeyException.class); - } - - @Test - @DisplayName("식별번호에 일치하는 모든 사용자를 조회한다.") - void findAllById() { - //given - User user1 = new User("a1@naver.com", "password", "김성빈1"); - User user2 = new User("a2@naver.com", "password2", "김성빈2"); - Long userId1 = userRepository.save(user1); - Long userId2 = userRepository.save(user2); - - //when - List users = userRepository.findAllById(Arrays.asList(userId1, userId2)); - - //then - assertThat(users).hasSize(2); - } - - @Test - @DisplayName("식별번호에 일치하는 사용자를 조회한다.") - void findById() { - //given - String email = "a1@naver.com"; - String password = "password"; - String name = "김성빈1"; - User user = new User(email, password, name); - Long userId = userRepository.save(user); - - //when - User fetchedUser = userRepository.findById(userId); - - //then - assertThat(fetchedUser) - .extracting("email", "password", "name") - .containsExactly(email, password, name); - } - - @Test - @DisplayName("식별번호에 일치하는 사용자가 존재하지 않을 경우, 예외가 발생한다.") - void findById_fail_empty_result() { - //when, then - assertThatIllegalArgumentException() - .isThrownBy(() -> userRepository.findById(0L)) - .withMessageContaining("해당하는 회원이 존재하지 않습니다."); - } -} diff --git a/src/test/java/playground/service/user/UserServiceTest.java b/src/test/java/playground/service/user/UserServiceTest.java index 24de132..b21695f 100644 --- a/src/test/java/playground/service/user/UserServiceTest.java +++ b/src/test/java/playground/service/user/UserServiceTest.java @@ -7,12 +7,13 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.dao.DuplicateKeyException; -import playground.controller.user.request.CreateUserRequest; import playground.domain.user.User; import playground.repository.user.UserRepository; +import playground.service.user.request.CreateUserRequest; import java.util.Collections; import java.util.List; +import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; @@ -78,7 +79,7 @@ void findAllById() { void findById() { //given User mockUser = mock(User.class); - given(userRepository.findById(anyLong())).willReturn(mockUser); + given(userRepository.findById(anyLong())).willReturn(Optional.of(mockUser)); //when User user = userService.findById(1L); From 7b6689d5534f16d7c3b496d1c0282d390a80839d Mon Sep 17 00:00:00 2001 From: Beenie93 Date: Fri, 19 Nov 2021 23:04:13 +0900 Subject: [PATCH 03/14] =?UTF-8?q?refactor=20:=20=EB=AC=B8=EC=84=9C,=20?= =?UTF-8?q?=EA=B2=B0=EC=9E=AC=EC=9E=90=20=EB=8F=84=EB=A9=94=EC=9D=B8=20JPA?= =?UTF-8?q?=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Beenie93 --- .../document/DocumentController.java | 2 +- .../playground/domain/document/Document.java | 77 +++++++----- .../domain/document/DocumentApproval.java | 55 +++++++-- .../domain/document/DocumentApprovals.java | 41 +++++++ .../document/{ => vo}/ApprovalState.java | 2 +- .../domain/document/{ => vo}/Category.java | 2 +- .../document/DocumentApprovalRepository.java | 56 --------- .../document/DocumentRepository.java | 76 ++---------- .../service/document/DocumentService.java | 56 ++++----- .../request/CreateDocumentRequest.java | 24 +--- .../response/SelectDocumentResponse.java | 17 +-- .../response/SelectSingleOutBoxResponse.java | 10 +- .../document/DocumentControllerTest.java | 2 +- .../domain/document/DocumentApprovalTest.java | 19 ++- .../document/DocumentApprovalsTest.java | 64 ++++++++++ .../domain/document/DocumentTest.java | 13 +- .../DocumentApprovalRepositoryTest.java | 59 --------- .../document/DocumentRepositoryTest.java | 112 ++++++++---------- .../service/document/DocumentServiceTest.java | 95 ++++++--------- 19 files changed, 369 insertions(+), 413 deletions(-) create mode 100644 src/main/java/playground/domain/document/DocumentApprovals.java rename src/main/java/playground/domain/document/{ => vo}/ApprovalState.java (85%) rename src/main/java/playground/domain/document/{ => vo}/Category.java (86%) delete mode 100644 src/main/java/playground/repository/document/DocumentApprovalRepository.java rename src/main/java/playground/{controller => service}/document/request/CreateDocumentRequest.java (60%) create mode 100644 src/test/java/playground/domain/document/DocumentApprovalsTest.java delete mode 100644 src/test/java/playground/repository/document/DocumentApprovalRepositoryTest.java diff --git a/src/main/java/playground/controller/document/DocumentController.java b/src/main/java/playground/controller/document/DocumentController.java index 56deb57..f959733 100644 --- a/src/main/java/playground/controller/document/DocumentController.java +++ b/src/main/java/playground/controller/document/DocumentController.java @@ -9,8 +9,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import playground.controller.document.request.CreateDocumentRequest; import playground.service.document.DocumentService; +import playground.service.document.request.CreateDocumentRequest; import playground.service.document.response.SelectDocumentResponse; import playground.service.document.response.SelectSingleOutBoxResponse; diff --git a/src/main/java/playground/domain/document/Document.java b/src/main/java/playground/domain/document/Document.java index d4fb7ac..ae420d6 100644 --- a/src/main/java/playground/domain/document/Document.java +++ b/src/main/java/playground/domain/document/Document.java @@ -1,51 +1,72 @@ package playground.domain.document; +import lombok.AccessLevel; import lombok.Builder; +import lombok.EqualsAndHashCode; import lombok.Getter; +import lombok.NoArgsConstructor; +import playground.domain.document.vo.ApprovalState; +import playground.domain.document.vo.Category; +import playground.domain.user.User; -import java.util.Objects; +import javax.persistence.Column; +import javax.persistence.Embedded; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; +import java.util.List; +@Entity @Getter +@EqualsAndHashCode(of = "id") +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(name = "document") public class Document { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "document_id") private Long id; + + @Column(name = "title", nullable = false) private String title; + + @Enumerated(value = EnumType.STRING) + @Column(name = "category", nullable = false) private Category category; + + @Column(name = "contents", nullable = false) private String contents; - private Long drafterId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "drafter_id") + private User drafter; + + @Embedded + private DocumentApprovals documentApprovals = new DocumentApprovals(); + + @Enumerated(value = EnumType.STRING) + @Column(name = "approval_state", nullable = false) private ApprovalState approvalState; @Builder - private Document(final String title, final String category, - final String contents, final Long drafterId) { + private Document(final String title, final Category category, + final String contents, final User drafter) { this.title = title; - this.category = Category.valueOf(category); + this.category = category; this.contents = contents; - this.drafterId = drafterId; + this.drafter = drafter; this.approvalState = ApprovalState.DRAFTING; } - @Builder(builderMethodName = "builderForDao", builderClassName = "BuilderForDao") - private Document(final Long id, final String title, final String category, - final String contents, final Long drafterId, final String approvalState) { - this.id = id; - this.title = title; - this.category = Category.valueOf(category); - this.contents = contents; - this.drafterId = drafterId; - this.approvalState = ApprovalState.valueOf(approvalState); - } - - @Override - public boolean equals(final Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - final Document document = (Document) o; - return Objects.equals(id, document.id); - } - - @Override - public int hashCode() { - return Objects.hash(id); + public void enrollApprovals(final List approvers, final Document document) { + documentApprovals.enroll(approvers, document); } } diff --git a/src/main/java/playground/domain/document/DocumentApproval.java b/src/main/java/playground/domain/document/DocumentApproval.java index f7f6545..f3f0b36 100644 --- a/src/main/java/playground/domain/document/DocumentApproval.java +++ b/src/main/java/playground/domain/document/DocumentApproval.java @@ -1,29 +1,68 @@ package playground.domain.document; +import lombok.AccessLevel; import lombok.Builder; +import lombok.EqualsAndHashCode; import lombok.Getter; +import lombok.NoArgsConstructor; +import playground.domain.document.vo.ApprovalState; +import playground.domain.user.User; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.OneToOne; +import javax.persistence.Table; + +@Entity @Getter +@EqualsAndHashCode(of = "id") +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(name = "document_approval") public class DocumentApproval { - private Long approverId; - private Long documentId; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "document_approval_id") + private Long id; + + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "approver_id") + private User approver; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "document_id") + private Document document; + + @Enumerated(value = EnumType.STRING) + @Column(name = "approval_state", nullable = false) private ApprovalState approvalState; + + @Column(name = "approval_order", nullable = false) private Integer approvalOrder; + + @Column(name = "approval_comment") private String approvalComment; @Builder - private DocumentApproval(final Long approverId, final Long documentId, final String approvalState, + private DocumentApproval(final User approver, final Document document, final ApprovalState approvalState, final Integer approvalOrder, final String approvalComment) { - this.approverId = approverId; - this.documentId = documentId; - this.approvalState = ApprovalState.valueOf(approvalState); + this.approver = approver; + this.document = document; + this.approvalState = approvalState; this.approvalOrder = approvalOrder; this.approvalComment = approvalComment; } - public static DocumentApproval of(final Long approverId, final Long documentId, final int approvalOrder) { - return new DocumentApproval(approverId, documentId, ApprovalState.DRAFTING.name(), + public static DocumentApproval of(final User approver, final Document document, final int approvalOrder) { + return new DocumentApproval(approver, document, ApprovalState.DRAFTING, approvalOrder, null); } } diff --git a/src/main/java/playground/domain/document/DocumentApprovals.java b/src/main/java/playground/domain/document/DocumentApprovals.java new file mode 100644 index 0000000..06325f9 --- /dev/null +++ b/src/main/java/playground/domain/document/DocumentApprovals.java @@ -0,0 +1,41 @@ +package playground.domain.document; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import playground.domain.user.User; + +import javax.persistence.CascadeType; +import javax.persistence.Embeddable; +import javax.persistence.OneToMany; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@Getter +@Embeddable +@NoArgsConstructor(access = AccessLevel.PUBLIC) +public class DocumentApprovals { + + @OneToMany(mappedBy = "document", cascade = CascadeType.ALL, orphanRemoval = true) + private List documentApprovals = new ArrayList<>(); + + public void enroll(final List approvers, final Document document) { + checkEmpty(); + + for (int i = 0; i < approvers.size(); i++) { + DocumentApproval documentApproval = DocumentApproval.of(approvers.get(i), document, i + 1); + documentApprovals.add(documentApproval); + } + } + + private void checkEmpty() { + if (!documentApprovals.isEmpty()) { + throw new IllegalStateException("결재자 추가 등록이 불가능합니다."); + } + } + + public List getDocumentApprovals() { + return Collections.unmodifiableList(documentApprovals); + } +} diff --git a/src/main/java/playground/domain/document/ApprovalState.java b/src/main/java/playground/domain/document/vo/ApprovalState.java similarity index 85% rename from src/main/java/playground/domain/document/ApprovalState.java rename to src/main/java/playground/domain/document/vo/ApprovalState.java index 15be5e0..4b28acb 100644 --- a/src/main/java/playground/domain/document/ApprovalState.java +++ b/src/main/java/playground/domain/document/vo/ApprovalState.java @@ -1,4 +1,4 @@ -package playground.domain.document; +package playground.domain.document.vo; import lombok.Getter; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/playground/domain/document/Category.java b/src/main/java/playground/domain/document/vo/Category.java similarity index 86% rename from src/main/java/playground/domain/document/Category.java rename to src/main/java/playground/domain/document/vo/Category.java index a68b3a1..24ea49b 100644 --- a/src/main/java/playground/domain/document/Category.java +++ b/src/main/java/playground/domain/document/vo/Category.java @@ -1,4 +1,4 @@ -package playground.domain.document; +package playground.domain.document.vo; import lombok.Getter; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/playground/repository/document/DocumentApprovalRepository.java b/src/main/java/playground/repository/document/DocumentApprovalRepository.java deleted file mode 100644 index f08ece9..0000000 --- a/src/main/java/playground/repository/document/DocumentApprovalRepository.java +++ /dev/null @@ -1,56 +0,0 @@ -package playground.repository.document; - -import org.springframework.jdbc.core.BatchPreparedStatementSetter; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.stereotype.Component; -import playground.domain.document.DocumentApproval; - -import javax.sql.DataSource; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.util.List; - -@Component -public class DocumentApprovalRepository { - - private final JdbcTemplate jdbcTemplate; - - public DocumentApprovalRepository(final DataSource dataSource) { - this.jdbcTemplate = new JdbcTemplate(dataSource); - } - - public void saveAll(final List documentApprovals) { - String saveQuery = "insert into document_approval (approver_id, document_id, approval_state, approval_order, approval_comment) " + - "values(?, ?, ?, ?, ?)"; - - jdbcTemplate.batchUpdate(saveQuery, new BatchPreparedStatementSetter() { - @Override - public void setValues(final PreparedStatement ps, final int i) throws SQLException { - DocumentApproval documentApproval = documentApprovals.get(i); - ps.setLong(1, documentApproval.getApproverId()); - ps.setLong(2, documentApproval.getDocumentId()); - ps.setString(3, documentApproval.getApprovalState().name()); - ps.setInt(4, documentApproval.getApprovalOrder()); - ps.setString(5, documentApproval.getApprovalComment()); - } - - @Override - public int getBatchSize() { - return documentApprovals.size(); - } - }); - } - - public List findAll() { - String selectAllQuery = "select * from document_approval"; - - return jdbcTemplate.query(selectAllQuery, (rs, rowNum) -> - DocumentApproval.builder() - .approverId(rs.getLong("approver_id")) - .approverId(rs.getLong("document_id")) - .approvalState(rs.getString("approval_state")) - .approvalOrder(rs.getInt("approval_order")) - .approvalComment(rs.getString("approval_comment")) - .build()); - } -} diff --git a/src/main/java/playground/repository/document/DocumentRepository.java b/src/main/java/playground/repository/document/DocumentRepository.java index 8c26ad9..2cff4a9 100644 --- a/src/main/java/playground/repository/document/DocumentRepository.java +++ b/src/main/java/playground/repository/document/DocumentRepository.java @@ -1,75 +1,19 @@ package playground.repository.document; -import org.springframework.dao.EmptyResultDataAccessException; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.support.GeneratedKeyHolder; -import org.springframework.jdbc.support.KeyHolder; -import org.springframework.stereotype.Component; -import playground.domain.document.ApprovalState; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import playground.domain.document.Document; +import playground.domain.document.vo.ApprovalState; -import javax.sql.DataSource; -import java.sql.PreparedStatement; -import java.sql.Statement; import java.util.List; +import java.util.Optional; -@Component -public class DocumentRepository { +public interface DocumentRepository extends JpaRepository { - private final JdbcTemplate jdbcTemplate; + @Query("select d from Document d join fetch d.drafter where d.id = :document_id") + Optional findByIdWithDrafter(@Param("document_id") final Long documentId); - public DocumentRepository(final DataSource dataSource) { - this.jdbcTemplate = new JdbcTemplate(dataSource); - } - - public Long save(final Document document) { - String saveQuery = "insert into document (title, category, contents, drafter_id, approval_state) " + - "values (?, ?, ?, ?, ?)"; - KeyHolder keyHolder = new GeneratedKeyHolder(); - - jdbcTemplate.update(connection -> { - PreparedStatement ps = connection - .prepareStatement(saveQuery, Statement.RETURN_GENERATED_KEYS); - ps.setString(1, document.getTitle()); - ps.setString(2, document.getCategory().name()); - ps.setString(3, document.getContents()); - ps.setLong(4, document.getDrafterId()); - ps.setString(5, document.getApprovalState().name()); - return ps; - }, keyHolder); - - return keyHolder.getKey().longValue(); - } - - public Document findById(final Long documentId) { - String selectQuery = "select * from document where id = ?"; - - try { - return jdbcTemplate.queryForObject(selectQuery, (rs, rowNum) -> - Document.builderForDao() - .id(rs.getLong("id")) - .title(rs.getString("title")) - .category(rs.getString("category")) - .contents(rs.getString("contents")) - .drafterId(rs.getLong("drafter_id")) - .approvalState(rs.getString("approval_state")) - .build(), documentId); - } catch (EmptyResultDataAccessException e) { - throw new IllegalArgumentException(String.format("[%d] 번호에 해당하는 문서가 존재하지 않습니다.", documentId)); - } - } - - public List findAllByDrafterIdAndApprovalState(final Long drafterId, final ApprovalState approvalState) { - String selectQuery = "select * from document where drafter_id = ? and approval_state = ? order by id desc"; - - return jdbcTemplate.query(selectQuery, (rs, rowNum) -> - Document.builderForDao() - .id(rs.getLong("id")) - .title(rs.getString("title")) - .category(rs.getString("category")) - .contents(rs.getString("contents")) - .drafterId(rs.getLong("drafter_id")) - .approvalState(rs.getString("approval_state")) - .build(), drafterId, approvalState.name()); - } + @Query("select d from Document d join fetch d.drafter where d.drafter.id = :drafter_id and d.approvalState = :approval_state") + List findAllWithDrafter(@Param("drafter_id") final Long drafterId, @Param("approval_state") final ApprovalState approvalState); } diff --git a/src/main/java/playground/service/document/DocumentService.java b/src/main/java/playground/service/document/DocumentService.java index 6a37a91..6c9c02d 100644 --- a/src/main/java/playground/service/document/DocumentService.java +++ b/src/main/java/playground/service/document/DocumentService.java @@ -2,18 +2,16 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import playground.controller.document.request.CreateDocumentRequest; -import playground.domain.document.ApprovalState; import playground.domain.document.Document; -import playground.domain.document.DocumentApproval; +import playground.domain.document.vo.ApprovalState; import playground.domain.user.User; -import playground.repository.document.DocumentApprovalRepository; import playground.repository.document.DocumentRepository; +import playground.service.document.request.CreateDocumentRequest; import playground.service.document.response.SelectDocumentResponse; import playground.service.document.response.SelectSingleOutBoxResponse; import playground.service.user.UserService; -import java.util.ArrayList; +import javax.persistence.EntityNotFoundException; import java.util.List; import java.util.stream.Collectors; @@ -21,57 +19,55 @@ public class DocumentService { private final DocumentRepository documentRepository; - private final DocumentApprovalRepository documentApprovalRepository; private final UserService userService; public DocumentService(final DocumentRepository documentRepository, - final DocumentApprovalRepository documentApprovalRepository, final UserService userService) { this.documentRepository = documentRepository; - this.documentApprovalRepository = documentApprovalRepository; this.userService = userService; } @Transactional public void save(final CreateDocumentRequest createDocumentRequest) { - Long drafterId = createDocumentRequest.getDrafterId(); List approverIds = createDocumentRequest.getApproverIds(); - checkUserExistence(drafterId, approverIds); - - Document document = createDocumentRequest.toDocument(); - Long documentId = documentRepository.save(document); + checkApprovalExistence(approverIds); - List documentApprovals = createDocumentRequest.toDocumentApprovals(documentId); - documentApprovalRepository.saveAll(documentApprovals); + Long drafterId = createDocumentRequest.getDrafterId(); + User drafter = userService.findById(drafterId); + Document document = createDocumentRequest.toDocument(drafter); + List approvers = findAllById(approverIds); + document.enrollApprovals(approvers, document); + documentRepository.save(document); } - private void checkUserExistence(final Long drafterId, final List approvalIds) { - ArrayList userIds = new ArrayList<>(); + private void checkApprovalExistence(final List approvalIds) { + List users = userService.findAllById(approvalIds); - if (!approvalIds.contains(drafterId)) { - userIds.add(drafterId); + if (approvalIds.size() != users.size()) { + throw new EntityNotFoundException(String.format("%s 식별번호와 일치하는 결재자를 모두 찾지 못했습니다.", approvalIds)); } + } - userIds.addAll(approvalIds); - - List users = userService.findAllById(userIds); - - if (userIds.size() != users.size()) { - throw new IllegalArgumentException("전달받은 회원 식별자와 일치하는 회원을 모두 찾지 못했습니다."); - } + private List findAllById(final List approverIds) { + return approverIds.stream() + .map(userService::findById) + .collect(Collectors.toList()); } @Transactional(readOnly = true) public SelectDocumentResponse select(final Long documentId) { - Document document = documentRepository.findById(documentId); - User user = userService.findById(document.getDrafterId()); + Document document = findByIdWithDrafter(documentId); + return new SelectDocumentResponse(document); + } - return new SelectDocumentResponse(document, user); + private Document findByIdWithDrafter(final Long documentId) { + return documentRepository.findByIdWithDrafter(documentId) + .orElseThrow(() -> new EntityNotFoundException(String.format("[%d] 식별번호에 해당하는 문서가 존재하지 않습니다.", documentId))); } @Transactional(readOnly = true) public List selectOutBox(final Long drafterId) { - List documents = documentRepository.findAllByDrafterIdAndApprovalState(drafterId, ApprovalState.DRAFTING); + List documents = documentRepository.findAllWithDrafter(drafterId, ApprovalState.DRAFTING); checkEmpty(documents); return documents.stream() diff --git a/src/main/java/playground/controller/document/request/CreateDocumentRequest.java b/src/main/java/playground/service/document/request/CreateDocumentRequest.java similarity index 60% rename from src/main/java/playground/controller/document/request/CreateDocumentRequest.java rename to src/main/java/playground/service/document/request/CreateDocumentRequest.java index 475409b..ce715a8 100644 --- a/src/main/java/playground/controller/document/request/CreateDocumentRequest.java +++ b/src/main/java/playground/service/document/request/CreateDocumentRequest.java @@ -1,16 +1,15 @@ -package playground.controller.document.request; +package playground.service.document.request; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; import playground.domain.document.Document; -import playground.domain.document.DocumentApproval; +import playground.domain.document.vo.Category; +import playground.domain.user.User; import javax.validation.constraints.Min; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotEmpty; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; @Getter @@ -41,23 +40,12 @@ public CreateDocumentRequest(final String title, final String category, final St this.approverIds = approverIds; } - public Document toDocument() { + public Document toDocument(final User drafter) { return Document.builder() .title(title) - .category(category) + .category(Category.valueOf(category)) .contents(contents) - .drafterId(drafterId) + .drafter(drafter) .build(); } - - public List toDocumentApprovals(final Long documentId) { - ArrayList documentApprovals = new ArrayList<>(); - - for (int i = 0; i < approverIds.size(); i++) { - DocumentApproval documentApproval = DocumentApproval.of(approverIds.get(i), documentId, i); - documentApprovals.add(documentApproval); - } - - return Collections.unmodifiableList(documentApprovals); - } } diff --git a/src/main/java/playground/service/document/response/SelectDocumentResponse.java b/src/main/java/playground/service/document/response/SelectDocumentResponse.java index be07618..dfaf3be 100644 --- a/src/main/java/playground/service/document/response/SelectDocumentResponse.java +++ b/src/main/java/playground/service/document/response/SelectDocumentResponse.java @@ -4,7 +4,8 @@ import lombok.Getter; import lombok.NoArgsConstructor; import playground.domain.document.Document; -import playground.domain.user.User; +import playground.domain.document.vo.ApprovalState; +import playground.domain.document.vo.Category; @Getter @NoArgsConstructor(access = AccessLevel.PRIVATE) @@ -12,22 +13,22 @@ public class SelectDocumentResponse { private Long id; private String title; - private String category; + private Category category; private String contents; private Long userId; - private String approvalState; + private ApprovalState approvalState; private String userName; private String categoryText; private String approvalStateText; - public SelectDocumentResponse(final Document document, final User user) { + public SelectDocumentResponse(final Document document) { this.id = document.getId(); this.title = document.getTitle(); - this.category = document.getCategory().name(); + this.category = document.getCategory(); this.contents = document.getContents(); - this.userId = user.getId(); - this.approvalState = document.getApprovalState().name(); - this.userName = user.getName(); + this.userId = document.getDrafter().getId(); + this.approvalState = document.getApprovalState(); + this.userName = document.getDrafter().getName(); this.categoryText = document.getCategory().getText(); this.approvalStateText = document.getApprovalState().getText(); } diff --git a/src/main/java/playground/service/document/response/SelectSingleOutBoxResponse.java b/src/main/java/playground/service/document/response/SelectSingleOutBoxResponse.java index a9b6bc9..e486493 100644 --- a/src/main/java/playground/service/document/response/SelectSingleOutBoxResponse.java +++ b/src/main/java/playground/service/document/response/SelectSingleOutBoxResponse.java @@ -4,6 +4,8 @@ import lombok.Getter; import lombok.NoArgsConstructor; import playground.domain.document.Document; +import playground.domain.document.vo.ApprovalState; +import playground.domain.document.vo.Category; @Getter @NoArgsConstructor(access = AccessLevel.PRIVATE) @@ -11,16 +13,16 @@ public class SelectSingleOutBoxResponse { private Long id; private String title; - private String category; - private String approvalState; + private Category category; + private ApprovalState approvalState; private String categoryText; private String approvalStateText; public SelectSingleOutBoxResponse(final Document document) { this.id = document.getId(); this.title = document.getTitle(); - this.category = document.getCategory().name(); - this.approvalState = document.getApprovalState().name(); + this.category = document.getCategory(); + this.approvalState = document.getApprovalState(); this.categoryText = document.getCategory().getText(); this.approvalStateText = document.getApprovalState().getText(); } diff --git a/src/test/java/playground/controller/document/DocumentControllerTest.java b/src/test/java/playground/controller/document/DocumentControllerTest.java index 50c2bf9..aef7f16 100644 --- a/src/test/java/playground/controller/document/DocumentControllerTest.java +++ b/src/test/java/playground/controller/document/DocumentControllerTest.java @@ -7,8 +7,8 @@ import org.mockito.Mock; import org.springframework.http.MediaType; import playground.common.AbstractControllerTest; -import playground.controller.document.request.CreateDocumentRequest; import playground.service.document.DocumentService; +import playground.service.document.request.CreateDocumentRequest; import java.util.Collections; import java.util.List; diff --git a/src/test/java/playground/domain/document/DocumentApprovalTest.java b/src/test/java/playground/domain/document/DocumentApprovalTest.java index 9fac8e1..3a6bbb3 100644 --- a/src/test/java/playground/domain/document/DocumentApprovalTest.java +++ b/src/test/java/playground/domain/document/DocumentApprovalTest.java @@ -2,6 +2,9 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import playground.domain.document.vo.ApprovalState; +import playground.domain.document.vo.Category; +import playground.domain.user.User; import static org.assertj.core.api.Assertions.assertThat; @@ -11,16 +14,22 @@ class DocumentApprovalTest { @DisplayName("결재 정보를 저장한다.") void create() { //given - long approverId = 1L; - long documentId = 1L; + User drafter = new User("test@naver.com", "Password123!", "drafter"); + User approver = new User("test@naver.com", "Password123!", "approver"); + Document document = Document.builder() + .drafter(drafter) + .category(Category.EDUCATION) + .title("교육비 정산") + .contents("교육비 정산 결재") + .build(); int approvalOrder = 1; //when - DocumentApproval documentApproval = DocumentApproval.of(approverId, documentId, approvalOrder); + DocumentApproval documentApproval = DocumentApproval.of(approver, document, approvalOrder); //then assertThat(documentApproval) - .extracting("approverId", "documentId", "approvalState", "approvalOrder", "approvalComment") - .containsExactly(approverId, documentId, ApprovalState.DRAFTING, approvalOrder, null); + .extracting("approver", "document", "approvalState", "approvalOrder", "approvalComment") + .containsExactly(approver, document, ApprovalState.DRAFTING, approvalOrder, null); } } diff --git a/src/test/java/playground/domain/document/DocumentApprovalsTest.java b/src/test/java/playground/domain/document/DocumentApprovalsTest.java new file mode 100644 index 0000000..9ee4e06 --- /dev/null +++ b/src/test/java/playground/domain/document/DocumentApprovalsTest.java @@ -0,0 +1,64 @@ +package playground.domain.document; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import playground.domain.document.vo.Category; +import playground.domain.user.User; + +import java.util.Arrays; +import java.util.Collections; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalStateException; + +class DocumentApprovalsTest { + + @Test + @DisplayName("결재자를 등록한다.") + void enroll() { + //given + User drafter = new User("test1@naver.com", "Password123!", "drafter"); + User approver1 = new User("test2@naver.com", "Password123!", "approver1"); + User approver2 = new User("test3@naver.com", "Password123!", "approver2"); + + Document document = Document.builder() + .drafter(drafter) + .category(Category.EDUCATION) + .title("교육비 정산") + .contents("교육비 정산 결재") + .build(); + + DocumentApprovals documentApprovals = new DocumentApprovals(); + + //when + documentApprovals.enroll(Arrays.asList(approver1, approver2), document); + + //then + assertThat(documentApprovals.getDocumentApprovals()).hasSize(2); + } + + @Test + @DisplayName("이미 결재자가 등록된 상태에서, 결재자를 추가할 경우 예외가 발생한다.") + void enroll_fail() { + //given + User drafter = new User("test1@naver.com", "Password123!", "drafter"); + User approver1 = new User("test2@naver.com", "Password123!", "approver1"); + User approver2 = new User("test3@naver.com", "Password123!", "approver2"); + + Document document = Document.builder() + .drafter(drafter) + .category(Category.EDUCATION) + .title("교육비 정산") + .contents("교육비 정산 결재") + .build(); + + DocumentApprovals documentApprovals = new DocumentApprovals(); + documentApprovals.enroll(Arrays.asList(approver1, approver2), document); + User approver3 = new User("test4@naver.com", "Password123!", "approver3"); + + //when, then + assertThatIllegalStateException() + .isThrownBy(() -> documentApprovals.enroll(Collections.singletonList(approver3), document)) + .withMessage("결재자 추가 등록이 불가능합니다."); + } +} diff --git a/src/test/java/playground/domain/document/DocumentTest.java b/src/test/java/playground/domain/document/DocumentTest.java index 3925027..a11a0a4 100644 --- a/src/test/java/playground/domain/document/DocumentTest.java +++ b/src/test/java/playground/domain/document/DocumentTest.java @@ -2,6 +2,9 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import playground.domain.document.vo.ApprovalState; +import playground.domain.document.vo.Category; +import playground.domain.user.User; import static org.assertj.core.api.Assertions.assertThat; @@ -12,21 +15,21 @@ class DocumentTest { void create() { //given String title = "교육비 결재"; - String category = "EDUCATION"; + Category category = Category.EDUCATION; String contents = "교육비"; - long drafterId = 1L; + User drafter = new User("test@naver.com", "Password123!", "drafter"); //when Document document = Document.builder() .title(title) .category(category) .contents(contents) - .drafterId(drafterId) + .drafter(drafter) .build(); //then assertThat(document) - .extracting("title", "category", "contents", "drafterId", "approvalState") - .containsExactly(title, Category.valueOf(category), contents, drafterId, ApprovalState.DRAFTING); + .extracting("title", "category", "contents", "drafter", "approvalState") + .containsExactly(title, category, contents, drafter, ApprovalState.DRAFTING); } } diff --git a/src/test/java/playground/repository/document/DocumentApprovalRepositoryTest.java b/src/test/java/playground/repository/document/DocumentApprovalRepositoryTest.java deleted file mode 100644 index 2347be3..0000000 --- a/src/test/java/playground/repository/document/DocumentApprovalRepositoryTest.java +++ /dev/null @@ -1,59 +0,0 @@ -package playground.repository.document; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.transaction.annotation.Transactional; -import playground.domain.document.Document; -import playground.domain.document.DocumentApproval; -import playground.domain.user.User; -import playground.repository.user.UserRepository; - -import java.util.ArrayList; - -import static org.assertj.core.api.Assertions.assertThat; - -@SpringBootTest -@Transactional -class DocumentApprovalRepositoryTest { - - @Autowired - private DocumentApprovalRepository documentApprovalRepository; - - @Autowired - private UserRepository userRepository; - - @Autowired - private DocumentRepository documentRepository; - - @Test - @DisplayName("결재 정보를 저장한다.") - void saveAll() { - //given - User drafter = new User("drafter@naver.com", "Password123!", "기안자"); - User approver1 = new User("approver1@naver.com", "Password123!", "김성빈1"); - User approver2 = new User("approver2@naver.com", "Password123!", "김성빈2"); - Long drafterId = userRepository.save(drafter); - Long approverId1 = userRepository.save(approver1); - Long approverId2 = userRepository.save(approver2); - - Document document = Document.builder() - .title("교육비 결재") - .drafterId(drafterId) - .category("EDUCATION") - .contents("교육비") - .build(); - Long documentId = documentRepository.save(document); - - ArrayList documentApprovals = new ArrayList<>(); - documentApprovals.add(DocumentApproval.of(approverId1, documentId, 1)); - documentApprovals.add(DocumentApproval.of(approverId2, documentId, 2)); - - //when - documentApprovalRepository.saveAll(documentApprovals); - - //then - assertThat(documentApprovalRepository.findAll()).hasSize(2); - } -} diff --git a/src/test/java/playground/repository/document/DocumentRepositoryTest.java b/src/test/java/playground/repository/document/DocumentRepositoryTest.java index 0bf50c7..491ae25 100644 --- a/src/test/java/playground/repository/document/DocumentRepositoryTest.java +++ b/src/test/java/playground/repository/document/DocumentRepositoryTest.java @@ -1,104 +1,88 @@ package playground.repository.document; +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.context.SpringBootTest; -import org.springframework.transaction.annotation.Transactional; -import playground.domain.document.ApprovalState; -import playground.domain.document.Category; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import playground.domain.document.Document; +import playground.domain.document.vo.ApprovalState; +import playground.domain.document.vo.Category; +import playground.domain.user.User; +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.PersistenceUnitUtil; import java.util.List; +import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; -@SpringBootTest -@Transactional +@DataJpaTest class DocumentRepositoryTest { @Autowired private DocumentRepository documentRepository; - @Test - @DisplayName("문서를 저장한다.") - void save() { - //given - Document document = Document.builder() - .title("교육비 결재") - .category("EDUCATION") - .contents("교육비") - .drafterId(1L) - .build(); + @Autowired + private EntityManager entityManager; - //when - long documentId = documentRepository.save(document); + @Autowired + private EntityManagerFactory entityManagerFactory; - //then - assertThat(documentId).isNotZero(); + private PersistenceUnitUtil persistenceUnitUtil; + + @BeforeEach + void setUp() { + persistenceUnitUtil = entityManagerFactory.getPersistenceUnitUtil(); } @Test - @DisplayName("문서를 조회한다.") - void findById() { + @DisplayName("기안자의 정보가 포함된 문서를 조회한다.") + void findByIdWithDrafter() { //given - String title = "교육비 결재"; - String category = "EDUCATION"; - String contents = "교육비"; - long drafterId = 1L; - + User drafter = new User("test@naver.com", "Password123!", "drafter"); + entityManager.persist(drafter); Document document = Document.builder() - .title(title) - .category(category) - .contents(contents) - .drafterId(drafterId) + .drafter(drafter) + .category(Category.EDUCATION) + .title("교육비 정산") + .contents("교육비 정산 결재") .build(); - long documentId = documentRepository.save(document); + documentRepository.save(document); + entityManager.flush(); + entityManager.clear(); //when - Document fetchedDocument = documentRepository.findById(documentId); + Optional fetchedDocument = documentRepository.findByIdWithDrafter(document.getId()); //then - assertThat(fetchedDocument) - .extracting("title", "category", "contents", "drafterId", "approvalState") - .containsExactly(title, Category.valueOf(category), contents, drafterId, ApprovalState.DRAFTING); + assertThat(fetchedDocument).isNotEmpty(); + assertThat(persistenceUnitUtil.isLoaded(fetchedDocument.get().getDrafter())).isTrue(); } - @Test - @DisplayName("식별번호에 일치하는 문서가 존재하지 않을 경우, 예외가 발생한다.") - void findById_fail_empty_result() { - //when, then - assertThatIllegalArgumentException() - .isThrownBy(() -> documentRepository.findById(0L)) - .withMessageContaining("해당하는 문서가 존재하지 않습니다."); - } @Test - @DisplayName("기안자 식별번호화 결재 상태가 일치하는 문서들을 조회한다.") - void findAllByDrafterIdAndApprovalState() { + @DisplayName("기안자의 정보가 포함된 조건에 맞는 모든 문서를 조회한다.") + void findAllWithDrafter() { //given - long drafterId = 1L; - Document document1 = Document.builder() - .title("교육비 결재") - .category("EDUCATION") - .contents("교육비") - .drafterId(drafterId) - .build(); - - Document document2 = Document.builder() - .title("운영비 결재") - .category("OPERATING_EXPENSES") - .contents("운영비") - .drafterId(drafterId) + User drafter = new User("test@naver.com", "Password123!", "drafter"); + entityManager.persist(drafter); + Document document = Document.builder() + .drafter(drafter) + .category(Category.EDUCATION) + .title("교육비 정산") + .contents("교육비 정산 결재") .build(); - documentRepository.save(document1); - documentRepository.save(document2); + documentRepository.save(document); + entityManager.flush(); + entityManager.clear(); //when - List documents = documentRepository.findAllByDrafterIdAndApprovalState(drafterId, ApprovalState.DRAFTING); + List documents = documentRepository.findAllWithDrafter(drafter.getId(), ApprovalState.DRAFTING); //then - assertThat(documents).hasSize(2); + assertThat(documents).hasSize(1); + assertThat(persistenceUnitUtil.isLoaded(documents.get(0).getDrafter())).isTrue(); } } diff --git a/src/test/java/playground/service/document/DocumentServiceTest.java b/src/test/java/playground/service/document/DocumentServiceTest.java index 508ba88..7e75a9a 100644 --- a/src/test/java/playground/service/document/DocumentServiceTest.java +++ b/src/test/java/playground/service/document/DocumentServiceTest.java @@ -6,22 +6,25 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import playground.controller.document.request.CreateDocumentRequest; -import playground.domain.document.ApprovalState; import playground.domain.document.Document; +import playground.domain.document.vo.ApprovalState; +import playground.domain.document.vo.Category; import playground.domain.user.User; -import playground.repository.document.DocumentApprovalRepository; import playground.repository.document.DocumentRepository; +import playground.service.document.request.CreateDocumentRequest; import playground.service.document.response.SelectDocumentResponse; import playground.service.document.response.SelectSingleOutBoxResponse; import playground.service.user.UserService; +import javax.persistence.EntityNotFoundException; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.anyLong; @@ -36,9 +39,6 @@ class DocumentServiceTest { @Mock private DocumentRepository documentRepository; - @Mock - private DocumentApprovalRepository documentApprovalRepository; - @Mock private UserService userService; @@ -60,38 +60,39 @@ void save() { //then verify(userService, times(1)).findAllById(anyList()); verify(documentRepository, times(1)).save(any(Document.class)); - verify(documentApprovalRepository, times(1)).saveAll(anyList()); } @Test - @DisplayName("기안자 또는 결재자의 정보가 존재하지 않을 경우, 예외가 발생한다.") - void save_fail_not_exist_drafter_or_approver() { + @DisplayName("결재자가 한 명이라도 존재하지 않을 경우, 예외가 발생한다.") + void save_fail_not_exist_approver() { //given CreateDocumentRequest createDocumentRequest = new CreateDocumentRequest("교육비 결재 요청", "EDUCATION", "교육비", 1L, Collections.singletonList(1L)); - String errorMessage = "전달받은 회원 식별자와 일치하는 회원을 모두 찾지 못했습니다."; + String errorMessage = "식별번호와 일치하는 결재자를 모두 찾지 못했습니다."; //when, then - assertThatIllegalArgumentException() - .isThrownBy(() -> documentService.save(createDocumentRequest)) - .withMessage(errorMessage); + assertThatThrownBy(() -> documentService.save(createDocumentRequest)) + .isInstanceOf(EntityNotFoundException.class) + .hasMessageContaining(errorMessage); } @Test @DisplayName("문서를 조회한다.") void select() { //given - Document document = Document.builderForDao() - .id(1L) - .title("교육비 결재") - .category("EDUCATION") - .contents("교육비") - .drafterId(1L) - .approvalState("DRAFTING") - .build(); - User user = new User("a@naver.com", "Password123!", "김성빈"); - given(documentRepository.findById(anyLong())).willReturn(document); - given(userService.findById(anyLong())).willReturn(user); + User drafter = mock(User.class); + given(drafter.getId()).willReturn(1L); + given(drafter.getName()).willReturn("기안자"); + + Document document = mock(Document.class); + given(document.getId()).willReturn(1L); + given(document.getDrafter()).willReturn(drafter); + given(document.getTitle()).willReturn("교육비 결재"); + given(document.getCategory()).willReturn(Category.EDUCATION); + given(document.getContents()).willReturn("교육비"); + given(document.getApprovalState()).willReturn(ApprovalState.DRAFTING); + + given(documentRepository.findByIdWithDrafter(anyLong())).willReturn(Optional.of(document)); //when SelectDocumentResponse selectDocumentResponse = documentService.select(1L); @@ -103,49 +104,27 @@ void select() { @Test @DisplayName("문서가 존재하지 않을 시, 예외가 발생한다.") void select_fail_not_found_document() { - //given - String errorMessage = "해당하는 문서가 존재하지 않습니다."; - given(documentRepository.findById(anyLong())).willThrow(new IllegalArgumentException(errorMessage)); - //when, then - assertThatIllegalArgumentException() - .isThrownBy(() -> documentService.select(1L)) - .withMessageContaining(errorMessage); - } - - @Test - @DisplayName("기안자가 존재하지 않을 시, 예외가 발생한다.") - void select_fail_not_found_user() { - //given - Document document = mock(Document.class); - given(documentRepository.findById(anyLong())).willReturn(document); - String errorMessage = "해당하는 회원이 존재하지 않습니다."; - given(userService.findById(anyLong())).willThrow(new IllegalArgumentException(errorMessage)); - - //when, then - assertThatIllegalArgumentException() - .isThrownBy(() -> documentService.select(1L)) - .withMessageContaining(errorMessage); + assertThatThrownBy(() -> documentService.select(1L)) + .isInstanceOf(EntityNotFoundException.class) + .hasMessageContaining("해당하는 문서가 존재하지 않습니다."); } @Test @DisplayName("Outbox 문서 리스트를 조회한다.") void selectOutBox() { //given - long drafterId = 1L; - Document document = Document.builderForDao() - .id(1L) - .title("교육비 결재") - .category("EDUCATION") - .contents("교육비") - .drafterId(drafterId) - .approvalState("DRAFTING") - .build(); - given(documentRepository.findAllByDrafterIdAndApprovalState(anyLong(), any(ApprovalState.class))) + Document document = mock(Document.class); + given(document.getId()).willReturn(1L); + given(document.getTitle()).willReturn("교육비 결재"); + given(document.getCategory()).willReturn(Category.EDUCATION); + given(document.getApprovalState()).willReturn(ApprovalState.DRAFTING); + + given(documentRepository.findAllWithDrafter(anyLong(), any(ApprovalState.class))) .willReturn(Collections.singletonList(document)); //when - List selectMultiOutboxResponse = documentService.selectOutBox(drafterId); + List selectMultiOutboxResponse = documentService.selectOutBox(1L); //then assertThat(selectMultiOutboxResponse).hasSize(1); @@ -156,7 +135,7 @@ void selectOutBox() { void selectOutBox_fail_empty_result() { //given String errorMessage = "현재 결재중인 문서가 존재하지 않습니다."; - given(documentRepository.findAllByDrafterIdAndApprovalState(anyLong(), any(ApprovalState.class))) + given(documentRepository.findAllWithDrafter(anyLong(), any(ApprovalState.class))) .willReturn(Collections.emptyList()); //when, then From ad3267e2e4f88505d1ee08feceb0b3f4f74f433b Mon Sep 17 00:00:00 2001 From: Beenie93 Date: Fri, 3 Dec 2021 20:55:01 +0900 Subject: [PATCH 04/14] =?UTF-8?q?feat=20:=20=ED=8C=80=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=EC=99=80=20=EC=97=B0=EA=B4=80=EA=B4=80=EA=B3=84=20?= =?UTF-8?q?=EB=A7=A4=ED=95=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Beenie93 --- .../java/playground/domain/team/Team.java | 45 +++++++++++++++ .../java/playground/domain/user/User.java | 12 +++- .../repository/team/TeamRepository.java | 11 ++++ .../playground/service/team/TeamService.java | 22 ++++++++ .../playground/service/user/UserService.java | 9 ++- .../user/request/CreateUserRequest.java | 11 +++- .../controller/user/UserControllerTest.java | 21 +++++-- .../domain/document/DocumentApprovalTest.java | 7 ++- .../document/DocumentApprovalsTest.java | 18 +++--- .../domain/document/DocumentTest.java | 9 ++- .../java/playground/domain/team/TeamTest.java | 24 ++++++++ .../java/playground/domain/user/UserTest.java | 9 ++- .../document/DocumentRepositoryTest.java | 9 ++- .../service/team/TeamServiceTest.java | 55 +++++++++++++++++++ .../service/user/UserServiceTest.java | 29 +++++++++- 15 files changed, 262 insertions(+), 29 deletions(-) create mode 100644 src/main/java/playground/domain/team/Team.java create mode 100644 src/main/java/playground/repository/team/TeamRepository.java create mode 100644 src/main/java/playground/service/team/TeamService.java create mode 100644 src/test/java/playground/domain/team/TeamTest.java create mode 100644 src/test/java/playground/service/team/TeamServiceTest.java diff --git a/src/main/java/playground/domain/team/Team.java b/src/main/java/playground/domain/team/Team.java new file mode 100644 index 0000000..bda4abe --- /dev/null +++ b/src/main/java/playground/domain/team/Team.java @@ -0,0 +1,45 @@ +package playground.domain.team; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import playground.domain.user.User; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import javax.persistence.UniqueConstraint; +import java.util.ArrayList; +import java.util.List; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(name = "team", uniqueConstraints = { + @UniqueConstraint(name = "team_name_contraint", columnNames = "name") +}) +public class Team { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "team_id") + private Long id; + + @Column(name = "name", nullable = false) + private String name; + + @OneToMany(mappedBy = "team") + private List users = new ArrayList<>(); + + public Team(final String name) { + this.name = name; + } + + public void addUser(final User user) { + this.users.add(user); + } +} diff --git a/src/main/java/playground/domain/user/User.java b/src/main/java/playground/domain/user/User.java index 5cbe1b6..69d1934 100644 --- a/src/main/java/playground/domain/user/User.java +++ b/src/main/java/playground/domain/user/User.java @@ -4,12 +4,16 @@ import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; +import playground.domain.team.Team; import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; import javax.persistence.Table; import javax.persistence.UniqueConstraint; @@ -36,10 +40,16 @@ public class User { @Column(name = "name", nullable = false) private String name; - public User(final String email, final String password, final String name) { + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "team_id") + private Team team; + + public User(final String email, final String password, final String name, final Team team) { this.email = email; this.password = password; this.name = name; + this.team = team; + this.team.addUser(this); } } diff --git a/src/main/java/playground/repository/team/TeamRepository.java b/src/main/java/playground/repository/team/TeamRepository.java new file mode 100644 index 0000000..e6cbfd5 --- /dev/null +++ b/src/main/java/playground/repository/team/TeamRepository.java @@ -0,0 +1,11 @@ +package playground.repository.team; + +import org.springframework.data.jpa.repository.JpaRepository; +import playground.domain.team.Team; + +import java.util.Optional; + +public interface TeamRepository extends JpaRepository { + + Optional findByName(final String teamName); +} diff --git a/src/main/java/playground/service/team/TeamService.java b/src/main/java/playground/service/team/TeamService.java new file mode 100644 index 0000000..66ef16e --- /dev/null +++ b/src/main/java/playground/service/team/TeamService.java @@ -0,0 +1,22 @@ +package playground.service.team; + +import org.springframework.stereotype.Service; +import playground.domain.team.Team; +import playground.repository.team.TeamRepository; + +import javax.persistence.EntityNotFoundException; + +@Service +public class TeamService { + + private final TeamRepository teamRepository; + + public TeamService(final TeamRepository teamRepository) { + this.teamRepository = teamRepository; + } + + public Team findByName(final String teamName) { + return teamRepository.findByName(teamName) + .orElseThrow(() -> new EntityNotFoundException(String.format("[%s] 팀 이름에 해당하는 팀이 존재하지 않습니다.", teamName))); + } +} diff --git a/src/main/java/playground/service/user/UserService.java b/src/main/java/playground/service/user/UserService.java index eeee95d..aa93fb8 100644 --- a/src/main/java/playground/service/user/UserService.java +++ b/src/main/java/playground/service/user/UserService.java @@ -3,8 +3,10 @@ import org.springframework.dao.DataIntegrityViolationException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import playground.domain.team.Team; import playground.domain.user.User; import playground.repository.user.UserRepository; +import playground.service.team.TeamService; import playground.service.user.request.CreateUserRequest; import javax.persistence.EntityNotFoundException; @@ -14,14 +16,17 @@ public class UserService { private final UserRepository userRepository; + private final TeamService teamService; - public UserService(final UserRepository userRepository) { + public UserService(final UserRepository userRepository, final TeamService teamService) { this.userRepository = userRepository; + this.teamService = teamService; } @Transactional public void save(final CreateUserRequest createUserRequest) { - User user = createUserRequest.toUser(); + Team team = teamService.findByName(createUserRequest.getTeamName()); + User user = createUserRequest.toUser(team); save(user); } diff --git a/src/main/java/playground/service/user/request/CreateUserRequest.java b/src/main/java/playground/service/user/request/CreateUserRequest.java index 1900ed7..bb30aef 100644 --- a/src/main/java/playground/service/user/request/CreateUserRequest.java +++ b/src/main/java/playground/service/user/request/CreateUserRequest.java @@ -3,6 +3,7 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; +import playground.domain.team.Team; import playground.domain.user.User; import javax.validation.constraints.Email; @@ -22,13 +23,17 @@ public class CreateUserRequest { @NotBlank private String name; - public CreateUserRequest(final String email, final String password, final String name) { + @NotBlank + private String teamName; + + public CreateUserRequest(final String email, final String password, final String name, final String teamName) { this.email = email; this.password = password; this.name = name; + this.teamName = teamName; } - public User toUser() { - return new User(email, password, name); + public User toUser(final Team team) { + return new User(email, password, name, team); } } diff --git a/src/test/java/playground/controller/user/UserControllerTest.java b/src/test/java/playground/controller/user/UserControllerTest.java index 59892dc..3824b3b 100644 --- a/src/test/java/playground/controller/user/UserControllerTest.java +++ b/src/test/java/playground/controller/user/UserControllerTest.java @@ -27,7 +27,7 @@ protected Object setController() { @Test @DisplayName("사용자 생성 요청을 받아 사용자를 생성 후, HTTP 201을 반환한다.") void create() throws Exception { - CreateUserRequest createUserRequest = new CreateUserRequest("seongbeen93@naver.com", "password", "김성빈"); + CreateUserRequest createUserRequest = new CreateUserRequest("seongbeen93@naver.com", "password", "김성빈", "정산시스템팀"); mockMvc.perform(post("/api/user") .accept(MediaType.APPLICATION_JSON) @@ -40,7 +40,7 @@ void create() throws Exception { @ValueSource(strings = {"idnaver.com", "", "@naver.com"}) @DisplayName("이메일 형식이 올바르지 않을 경우, 예외가 발생한다.") void create_fail_invalid_email(String invalidEmail) throws Exception { - CreateUserRequest createUserRequest = new CreateUserRequest(invalidEmail, "password", "김성빈"); + CreateUserRequest createUserRequest = new CreateUserRequest(invalidEmail, "password", "김성빈", "정산시스템팀"); mockMvc.perform(post("/api/user") .accept(MediaType.APPLICATION_JSON) @@ -53,7 +53,7 @@ void create_fail_invalid_email(String invalidEmail) throws Exception { @NullAndEmptySource @DisplayName("비밀번호가 공백 또는 null있을 경우, 예외가 발생한다.") void create_fail_empty_password(String invalidPassword) throws Exception { - CreateUserRequest createUserRequest = new CreateUserRequest("seongbeen93@naver.com", invalidPassword, "김성빈"); + CreateUserRequest createUserRequest = new CreateUserRequest("seongbeen93@naver.com", invalidPassword, "김성빈", "정산시스템팀"); mockMvc.perform(post("/api/user") .accept(MediaType.APPLICATION_JSON) @@ -66,7 +66,20 @@ void create_fail_empty_password(String invalidPassword) throws Exception { @NullAndEmptySource @DisplayName("이름이 공백 또는 null일 경우, 예외가 발생한다.") void create_fail_empty_name(String invalidName) throws Exception { - CreateUserRequest createUserRequest = new CreateUserRequest("seongbeen93@naver.com", "password", invalidName); + CreateUserRequest createUserRequest = new CreateUserRequest("seongbeen93@naver.com", "password", invalidName, "정산시스템팀"); + + mockMvc.perform(post("/api/user") + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(createUserRequest))) + .andExpect(status().isBadRequest()); + } + + @ParameterizedTest + @NullAndEmptySource + @DisplayName("팀명이 공백 또는 null일 경우, 예외가 발생한다.") + void create_fail_empty_team(String invalidTeamName) throws Exception { + CreateUserRequest createUserRequest = new CreateUserRequest("seongbeen93@naver.com", "password", "김성빈", invalidTeamName); mockMvc.perform(post("/api/user") .accept(MediaType.APPLICATION_JSON) diff --git a/src/test/java/playground/domain/document/DocumentApprovalTest.java b/src/test/java/playground/domain/document/DocumentApprovalTest.java index 3a6bbb3..8da8fd5 100644 --- a/src/test/java/playground/domain/document/DocumentApprovalTest.java +++ b/src/test/java/playground/domain/document/DocumentApprovalTest.java @@ -4,9 +4,11 @@ import org.junit.jupiter.api.Test; import playground.domain.document.vo.ApprovalState; import playground.domain.document.vo.Category; +import playground.domain.team.Team; import playground.domain.user.User; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; class DocumentApprovalTest { @@ -14,8 +16,9 @@ class DocumentApprovalTest { @DisplayName("결재 정보를 저장한다.") void create() { //given - User drafter = new User("test@naver.com", "Password123!", "drafter"); - User approver = new User("test@naver.com", "Password123!", "approver"); + Team team = mock(Team.class); + User drafter = new User("test@naver.com", "Password123!", "drafter", team); + User approver = new User("test@naver.com", "Password123!", "approver", team); Document document = Document.builder() .drafter(drafter) .category(Category.EDUCATION) diff --git a/src/test/java/playground/domain/document/DocumentApprovalsTest.java b/src/test/java/playground/domain/document/DocumentApprovalsTest.java index 9ee4e06..66889cd 100644 --- a/src/test/java/playground/domain/document/DocumentApprovalsTest.java +++ b/src/test/java/playground/domain/document/DocumentApprovalsTest.java @@ -3,6 +3,7 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import playground.domain.document.vo.Category; +import playground.domain.team.Team; import playground.domain.user.User; import java.util.Arrays; @@ -10,6 +11,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalStateException; +import static org.mockito.Mockito.mock; class DocumentApprovalsTest { @@ -17,9 +19,10 @@ class DocumentApprovalsTest { @DisplayName("결재자를 등록한다.") void enroll() { //given - User drafter = new User("test1@naver.com", "Password123!", "drafter"); - User approver1 = new User("test2@naver.com", "Password123!", "approver1"); - User approver2 = new User("test3@naver.com", "Password123!", "approver2"); + Team team = mock(Team.class); + User drafter = new User("test1@naver.com", "Password123!", "drafter", team); + User approver1 = new User("test2@naver.com", "Password123!", "approver1", team); + User approver2 = new User("test3@naver.com", "Password123!", "approver2", team); Document document = Document.builder() .drafter(drafter) @@ -41,9 +44,10 @@ void enroll() { @DisplayName("이미 결재자가 등록된 상태에서, 결재자를 추가할 경우 예외가 발생한다.") void enroll_fail() { //given - User drafter = new User("test1@naver.com", "Password123!", "drafter"); - User approver1 = new User("test2@naver.com", "Password123!", "approver1"); - User approver2 = new User("test3@naver.com", "Password123!", "approver2"); + Team team = mock(Team.class); + User drafter = new User("test1@naver.com", "Password123!", "drafter", team); + User approver1 = new User("test2@naver.com", "Password123!", "approver1", team); + User approver2 = new User("test3@naver.com", "Password123!", "approver2", team); Document document = Document.builder() .drafter(drafter) @@ -54,7 +58,7 @@ void enroll_fail() { DocumentApprovals documentApprovals = new DocumentApprovals(); documentApprovals.enroll(Arrays.asList(approver1, approver2), document); - User approver3 = new User("test4@naver.com", "Password123!", "approver3"); + User approver3 = new User("test4@naver.com", "Password123!", "approver3", team); //when, then assertThatIllegalStateException() diff --git a/src/test/java/playground/domain/document/DocumentTest.java b/src/test/java/playground/domain/document/DocumentTest.java index a11a0a4..eb5a1e7 100644 --- a/src/test/java/playground/domain/document/DocumentTest.java +++ b/src/test/java/playground/domain/document/DocumentTest.java @@ -4,9 +4,11 @@ import org.junit.jupiter.api.Test; import playground.domain.document.vo.ApprovalState; import playground.domain.document.vo.Category; +import playground.domain.team.Team; import playground.domain.user.User; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; class DocumentTest { @@ -17,7 +19,8 @@ void create() { String title = "교육비 결재"; Category category = Category.EDUCATION; String contents = "교육비"; - User drafter = new User("test@naver.com", "Password123!", "drafter"); + Team team = mock(Team.class); + User drafter = new User("test@naver.com", "Password123!", "drafter", team); //when Document document = Document.builder() @@ -29,7 +32,7 @@ void create() { //then assertThat(document) - .extracting("title", "category", "contents", "drafter", "approvalState") - .containsExactly(title, category, contents, drafter, ApprovalState.DRAFTING); + .extracting("title", "category", "contents", "drafter", "approvalState", "team") + .containsExactly(title, category, contents, drafter, ApprovalState.DRAFTING, team); } } diff --git a/src/test/java/playground/domain/team/TeamTest.java b/src/test/java/playground/domain/team/TeamTest.java new file mode 100644 index 0000000..02e0309 --- /dev/null +++ b/src/test/java/playground/domain/team/TeamTest.java @@ -0,0 +1,24 @@ +package playground.domain.team; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TeamTest { + + @Test + @DisplayName("팀을 생성한다.") + void create() { + //given + String name = "정산시스템팀"; + + //when + Team team = new Team(name); + + //then + assertThat(team) + .extracting("name") + .isEqualTo(name); + } +} diff --git a/src/test/java/playground/domain/user/UserTest.java b/src/test/java/playground/domain/user/UserTest.java index 95ad833..c04053b 100644 --- a/src/test/java/playground/domain/user/UserTest.java +++ b/src/test/java/playground/domain/user/UserTest.java @@ -2,8 +2,10 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import playground.domain.team.Team; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; class UserTest { @@ -11,16 +13,17 @@ class UserTest { @DisplayName("사용자를 생성한다.") void create() { //given + Team team = mock(Team.class); String email = "seongbeen93@naver.com"; String password = "password"; String name = "김성빈"; //when - User user = new User(email, password, name); + User user = new User(email, password, name, team); //then assertThat(user) - .extracting("email", "password", "name") - .containsExactly(email, password, name); + .extracting("email", "password", "name", "team") + .containsExactly(email, password, name, team); } } diff --git a/src/test/java/playground/repository/document/DocumentRepositoryTest.java b/src/test/java/playground/repository/document/DocumentRepositoryTest.java index 491ae25..4311597 100644 --- a/src/test/java/playground/repository/document/DocumentRepositoryTest.java +++ b/src/test/java/playground/repository/document/DocumentRepositoryTest.java @@ -8,6 +8,7 @@ import playground.domain.document.Document; import playground.domain.document.vo.ApprovalState; import playground.domain.document.vo.Category; +import playground.domain.team.Team; import playground.domain.user.User; import javax.persistence.EntityManager; @@ -41,7 +42,9 @@ void setUp() { @DisplayName("기안자의 정보가 포함된 문서를 조회한다.") void findByIdWithDrafter() { //given - User drafter = new User("test@naver.com", "Password123!", "drafter"); + Team team = new Team("정산시스템팀"); + entityManager.persist(team); + User drafter = new User("test@naver.com", "Password123!", "drafter", team); entityManager.persist(drafter); Document document = Document.builder() .drafter(drafter) @@ -66,7 +69,9 @@ void findByIdWithDrafter() { @DisplayName("기안자의 정보가 포함된 조건에 맞는 모든 문서를 조회한다.") void findAllWithDrafter() { //given - User drafter = new User("test@naver.com", "Password123!", "drafter"); + Team team = new Team("정산시스템팀"); + entityManager.persist(team); + User drafter = new User("test@naver.com", "Password123!", "drafter", team); entityManager.persist(drafter); Document document = Document.builder() .drafter(drafter) diff --git a/src/test/java/playground/service/team/TeamServiceTest.java b/src/test/java/playground/service/team/TeamServiceTest.java new file mode 100644 index 0000000..75e4d68 --- /dev/null +++ b/src/test/java/playground/service/team/TeamServiceTest.java @@ -0,0 +1,55 @@ +package playground.service.team; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import playground.domain.team.Team; +import playground.repository.team.TeamRepository; + +import javax.persistence.EntityNotFoundException; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; + +@ExtendWith(MockitoExtension.class) +class TeamServiceTest { + + @Mock + private TeamRepository teamRepository; + + @InjectMocks + private TeamService teamService; + + @Test + @DisplayName("팀 이름을 팀을 조회한다.") + void findByName() { + //given + String name = "정산서비스팀"; + Team team = new Team(name); + given(teamRepository.findByName(anyString())).willReturn(Optional.of(team)); + + //when + Team fetchedTeam = teamService.findByName(name); + + //then + assertThat(fetchedTeam).isEqualTo(team); + } + + @Test + @DisplayName("팀 이름과 일치하는 팀이 존재하지 않을 경우, 예외가 발생한다.") + void findByName_fail_not_found() { + //given + given(teamRepository.findByName(anyString())).willReturn(Optional.empty()); + + //when, then + assertThatThrownBy(() -> teamService.findByName("존재하지 않는 팀 이름")) + .isInstanceOf(EntityNotFoundException.class) + .hasMessageContaining("팀이 존재하지 않습니다."); + } +} diff --git a/src/test/java/playground/service/user/UserServiceTest.java b/src/test/java/playground/service/user/UserServiceTest.java index b21695f..f3df827 100644 --- a/src/test/java/playground/service/user/UserServiceTest.java +++ b/src/test/java/playground/service/user/UserServiceTest.java @@ -7,8 +7,10 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.dao.DuplicateKeyException; +import playground.domain.team.Team; import playground.domain.user.User; import playground.repository.user.UserRepository; +import playground.service.team.TeamService; import playground.service.user.request.CreateUserRequest; import java.util.Collections; @@ -20,6 +22,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -31,6 +34,9 @@ class UserServiceTest { @Mock private UserRepository userRepository; + @Mock + private TeamService teamService; + @InjectMocks private UserService userService; @@ -38,7 +44,9 @@ class UserServiceTest { @DisplayName("사용자를 저장한다.") void save() { //given - CreateUserRequest createUserRequest = new CreateUserRequest("a@naver.com", "Password123!", "김성빈"); + Team team = mock(Team.class); + given(teamService.findByName(anyString())).willReturn(team); + CreateUserRequest createUserRequest = new CreateUserRequest("a@naver.com", "Password123!", "김성빈", "정산시스템팀"); //when userService.save(createUserRequest); @@ -51,8 +59,25 @@ void save() { @DisplayName("중복된 이메일일 경우, 예외가 발생한다.") void save_fail_duplicated_email() { //given - CreateUserRequest createUserRequest = new CreateUserRequest("a@naver.com", "Password123!", "김성빈"); + Team team = mock(Team.class); + given(teamService.findByName(anyString())).willReturn(team); + given(userRepository.save(any(User.class))).willThrow(new DuplicateKeyException("이메일 중복")); + CreateUserRequest createUserRequest = new CreateUserRequest("a@naver.com", "Password123!", "김성빈", "정산시스템팀"); + + //when, then + assertThatIllegalArgumentException() + .isThrownBy(() -> userService.save(createUserRequest)) + .withMessageContaining("이미 가입된 이메일입니다."); + } + + @Test + @DisplayName("팀이 존재하지 않을 경우, 에외가 발생한다.") + void save_fail_team_not_found() { + //given + Team team = mock(Team.class); + given(teamService.findByName(anyString())).willReturn(team); given(userRepository.save(any(User.class))).willThrow(new DuplicateKeyException("이메일 중복")); + CreateUserRequest createUserRequest = new CreateUserRequest("a@naver.com", "Password123!", "김성빈", "정산시스템팀"); //when, then assertThatIllegalArgumentException() From b4507f7f3e85b901e71b2b5cbaaf8756d3fc2133 Mon Sep 17 00:00:00 2001 From: Beenie93 Date: Fri, 3 Dec 2021 21:22:29 +0900 Subject: [PATCH 05/14] =?UTF-8?q?feat=20:=20=ED=8C=80=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=20API=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Beenie93 --- .../controller/team/TeamController.java | 29 ++++++++++ .../playground/service/team/TeamService.java | 6 ++ .../team/request/CreateTeamRequest.java | 25 ++++++++ .../controller/team/TeamControllerTest.java | 57 +++++++++++++++++++ .../domain/document/DocumentTest.java | 4 +- .../service/team/TeamServiceTest.java | 17 ++++++ 6 files changed, 136 insertions(+), 2 deletions(-) create mode 100644 src/main/java/playground/controller/team/TeamController.java create mode 100644 src/main/java/playground/service/team/request/CreateTeamRequest.java create mode 100644 src/test/java/playground/controller/team/TeamControllerTest.java diff --git a/src/main/java/playground/controller/team/TeamController.java b/src/main/java/playground/controller/team/TeamController.java new file mode 100644 index 0000000..3b8dc01 --- /dev/null +++ b/src/main/java/playground/controller/team/TeamController.java @@ -0,0 +1,29 @@ +package playground.controller.team; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import playground.service.team.TeamService; +import playground.service.team.request.CreateTeamRequest; + +import javax.validation.Valid; + +@RestController +@RequestMapping(path = "/api/teams") +public class TeamController { + + private final TeamService teamService; + + public TeamController(final TeamService teamService) { + this.teamService = teamService; + } + + @PostMapping + public ResponseEntity create(@RequestBody @Valid final CreateTeamRequest createTeamRequest) { + teamService.save(createTeamRequest); + return new ResponseEntity<>(HttpStatus.CREATED); + } +} diff --git a/src/main/java/playground/service/team/TeamService.java b/src/main/java/playground/service/team/TeamService.java index 66ef16e..a1b7fec 100644 --- a/src/main/java/playground/service/team/TeamService.java +++ b/src/main/java/playground/service/team/TeamService.java @@ -3,6 +3,7 @@ import org.springframework.stereotype.Service; import playground.domain.team.Team; import playground.repository.team.TeamRepository; +import playground.service.team.request.CreateTeamRequest; import javax.persistence.EntityNotFoundException; @@ -19,4 +20,9 @@ public Team findByName(final String teamName) { return teamRepository.findByName(teamName) .orElseThrow(() -> new EntityNotFoundException(String.format("[%s] 팀 이름에 해당하는 팀이 존재하지 않습니다.", teamName))); } + + public void save(final CreateTeamRequest createTeamRequest) { + Team team = createTeamRequest.toTeam(); + teamRepository.save(team); + } } diff --git a/src/main/java/playground/service/team/request/CreateTeamRequest.java b/src/main/java/playground/service/team/request/CreateTeamRequest.java new file mode 100644 index 0000000..5030bb6 --- /dev/null +++ b/src/main/java/playground/service/team/request/CreateTeamRequest.java @@ -0,0 +1,25 @@ +package playground.service.team.request; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import playground.domain.team.Team; + +import javax.validation.constraints.NotBlank; + + +@Getter +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class CreateTeamRequest { + + @NotBlank + private String name; + + public CreateTeamRequest(final String name) { + this.name = name; + } + + public Team toTeam() { + return new Team(name); + } +} diff --git a/src/test/java/playground/controller/team/TeamControllerTest.java b/src/test/java/playground/controller/team/TeamControllerTest.java new file mode 100644 index 0000000..eaf81b0 --- /dev/null +++ b/src/test/java/playground/controller/team/TeamControllerTest.java @@ -0,0 +1,57 @@ +package playground.controller.team; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullAndEmptySource; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.MediaType; +import playground.common.AbstractControllerTest; +import playground.service.team.TeamService; +import playground.service.team.request.CreateTeamRequest; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@ExtendWith(MockitoExtension.class) +class TeamControllerTest extends AbstractControllerTest { + + @Mock + private TeamService teamService; + + @InjectMocks + private TeamController teamController; + + @Override + protected Object setController() { + return teamController; + } + + @Test + @DisplayName("팀 생성 요청을 받아 팀을 생성 후, HTTP 201을 반환한다.") + void create() throws Exception { + CreateTeamRequest createTeamRequest = new CreateTeamRequest("정산시스템팀"); + + mockMvc.perform(post("/api/teams") + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(createTeamRequest))) + .andExpect(status().isCreated()); + } + + @ParameterizedTest + @NullAndEmptySource + @DisplayName("팀 이름이 공백 또는 null있을 경우, 예외가 발생한다.") + void create_fail_empty_name(String invalidName) throws Exception { + CreateTeamRequest createTeamRequest = new CreateTeamRequest(invalidName); + + mockMvc.perform(post("/api/teams") + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(createTeamRequest))) + .andExpect(status().isBadRequest()); + } +} diff --git a/src/test/java/playground/domain/document/DocumentTest.java b/src/test/java/playground/domain/document/DocumentTest.java index eb5a1e7..fd6fb2b 100644 --- a/src/test/java/playground/domain/document/DocumentTest.java +++ b/src/test/java/playground/domain/document/DocumentTest.java @@ -32,7 +32,7 @@ void create() { //then assertThat(document) - .extracting("title", "category", "contents", "drafter", "approvalState", "team") - .containsExactly(title, category, contents, drafter, ApprovalState.DRAFTING, team); + .extracting("title", "category", "contents", "drafter", "approvalState") + .containsExactly(title, category, contents, drafter, ApprovalState.DRAFTING); } } diff --git a/src/test/java/playground/service/team/TeamServiceTest.java b/src/test/java/playground/service/team/TeamServiceTest.java index 75e4d68..ede968d 100644 --- a/src/test/java/playground/service/team/TeamServiceTest.java +++ b/src/test/java/playground/service/team/TeamServiceTest.java @@ -8,14 +8,18 @@ import org.mockito.junit.jupiter.MockitoExtension; import playground.domain.team.Team; import playground.repository.team.TeamRepository; +import playground.service.team.request.CreateTeamRequest; import javax.persistence.EntityNotFoundException; import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; @ExtendWith(MockitoExtension.class) class TeamServiceTest { @@ -52,4 +56,17 @@ void findByName_fail_not_found() { .isInstanceOf(EntityNotFoundException.class) .hasMessageContaining("팀이 존재하지 않습니다."); } + + @Test + @DisplayName("팀을 저장한다.") + void save() { + //given + CreateTeamRequest createTeamRequest = new CreateTeamRequest("정산시스템팀"); + + //when + teamService.save(createTeamRequest); + + //then + verify(teamRepository, times(1)).save(any(Team.class)); + } } From 706ef054ad779bcb0e7d01745212f86f0c4ac33a Mon Sep 17 00:00:00 2001 From: Beenie93 Date: Fri, 3 Dec 2021 21:23:22 +0900 Subject: [PATCH 06/14] =?UTF-8?q?refactor=20:=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=20api=20=EA=B2=BD=EB=A1=9C=20user=20->=20users?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Beenie93 --- .../playground/controller/user/UserController.java | 2 +- .../playground/controller/user/UserControllerTest.java | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/playground/controller/user/UserController.java b/src/main/java/playground/controller/user/UserController.java index 9a130db..3447a74 100644 --- a/src/main/java/playground/controller/user/UserController.java +++ b/src/main/java/playground/controller/user/UserController.java @@ -12,7 +12,7 @@ import javax.validation.Valid; @RestController -@RequestMapping(path = "/api/user") +@RequestMapping(path = "/api/users") public class UserController { private final UserService userService; diff --git a/src/test/java/playground/controller/user/UserControllerTest.java b/src/test/java/playground/controller/user/UserControllerTest.java index 3824b3b..16d9562 100644 --- a/src/test/java/playground/controller/user/UserControllerTest.java +++ b/src/test/java/playground/controller/user/UserControllerTest.java @@ -29,7 +29,7 @@ protected Object setController() { void create() throws Exception { CreateUserRequest createUserRequest = new CreateUserRequest("seongbeen93@naver.com", "password", "김성빈", "정산시스템팀"); - mockMvc.perform(post("/api/user") + mockMvc.perform(post("/api/users") .accept(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(createUserRequest))) @@ -42,7 +42,7 @@ void create() throws Exception { void create_fail_invalid_email(String invalidEmail) throws Exception { CreateUserRequest createUserRequest = new CreateUserRequest(invalidEmail, "password", "김성빈", "정산시스템팀"); - mockMvc.perform(post("/api/user") + mockMvc.perform(post("/api/users") .accept(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(createUserRequest))) @@ -55,7 +55,7 @@ void create_fail_invalid_email(String invalidEmail) throws Exception { void create_fail_empty_password(String invalidPassword) throws Exception { CreateUserRequest createUserRequest = new CreateUserRequest("seongbeen93@naver.com", invalidPassword, "김성빈", "정산시스템팀"); - mockMvc.perform(post("/api/user") + mockMvc.perform(post("/api/users") .accept(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(createUserRequest))) @@ -68,7 +68,7 @@ void create_fail_empty_password(String invalidPassword) throws Exception { void create_fail_empty_name(String invalidName) throws Exception { CreateUserRequest createUserRequest = new CreateUserRequest("seongbeen93@naver.com", "password", invalidName, "정산시스템팀"); - mockMvc.perform(post("/api/user") + mockMvc.perform(post("/api/users") .accept(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(createUserRequest))) @@ -81,7 +81,7 @@ void create_fail_empty_name(String invalidName) throws Exception { void create_fail_empty_team(String invalidTeamName) throws Exception { CreateUserRequest createUserRequest = new CreateUserRequest("seongbeen93@naver.com", "password", "김성빈", invalidTeamName); - mockMvc.perform(post("/api/user") + mockMvc.perform(post("/api/users") .accept(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(createUserRequest))) From 95c06065fbccb79a26a2007a510349ce9f28ad49 Mon Sep 17 00:00:00 2001 From: Beenie93 Date: Fri, 3 Dec 2021 22:22:57 +0900 Subject: [PATCH 07/14] =?UTF-8?q?feat=20:=20=EC=A0=84=EC=B2=B4=20=ED=8C=80?= =?UTF-8?q?=20=EC=A1=B0=ED=9A=8C=20API=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Beenie93 --- .../controller/team/TeamController.java | 8 ++++ .../playground/service/team/TeamService.java | 29 +++++++++++- .../team/response/SelectTeamResponse.java | 19 ++++++++ .../team/response/SelectTeamsResponse.java | 23 ++++++++++ src/main/resources/data.sql | 14 ++++-- .../controller/team/TeamControllerTest.java | 9 ++++ .../document/DocumentRepositoryTest.java | 1 - .../service/team/TeamServiceTest.java | 45 +++++++++++++++++++ 8 files changed, 142 insertions(+), 6 deletions(-) create mode 100644 src/main/java/playground/service/team/response/SelectTeamResponse.java create mode 100644 src/main/java/playground/service/team/response/SelectTeamsResponse.java diff --git a/src/main/java/playground/controller/team/TeamController.java b/src/main/java/playground/controller/team/TeamController.java index 3b8dc01..a9488e2 100644 --- a/src/main/java/playground/controller/team/TeamController.java +++ b/src/main/java/playground/controller/team/TeamController.java @@ -2,12 +2,14 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import playground.service.team.TeamService; import playground.service.team.request.CreateTeamRequest; +import playground.service.team.response.SelectTeamsResponse; import javax.validation.Valid; @@ -26,4 +28,10 @@ public ResponseEntity create(@RequestBody @Valid final CreateTeamRequest c teamService.save(createTeamRequest); return new ResponseEntity<>(HttpStatus.CREATED); } + + @GetMapping + public ResponseEntity selectAll() { + SelectTeamsResponse selectTeamsResponse = teamService.selectAll(); + return ResponseEntity.ok(selectTeamsResponse); + } } diff --git a/src/main/java/playground/service/team/TeamService.java b/src/main/java/playground/service/team/TeamService.java index a1b7fec..e5b9f6d 100644 --- a/src/main/java/playground/service/team/TeamService.java +++ b/src/main/java/playground/service/team/TeamService.java @@ -1,11 +1,15 @@ package playground.service.team; +import org.springframework.dao.DataIntegrityViolationException; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import playground.domain.team.Team; import playground.repository.team.TeamRepository; import playground.service.team.request.CreateTeamRequest; +import playground.service.team.response.SelectTeamsResponse; import javax.persistence.EntityNotFoundException; +import java.util.List; @Service public class TeamService { @@ -16,13 +20,36 @@ public TeamService(final TeamRepository teamRepository) { this.teamRepository = teamRepository; } + @Transactional(readOnly = true) public Team findByName(final String teamName) { return teamRepository.findByName(teamName) .orElseThrow(() -> new EntityNotFoundException(String.format("[%s] 팀 이름에 해당하는 팀이 존재하지 않습니다.", teamName))); } + @Transactional public void save(final CreateTeamRequest createTeamRequest) { Team team = createTeamRequest.toTeam(); - teamRepository.save(team); + save(team); + } + + private void save(final Team team) { + try { + teamRepository.save(team); + } catch (DataIntegrityViolationException e) { + throw new IllegalArgumentException(String.format("[%s] 이미 존재하는 팀입니다.", team.getName())); + } + } + + @Transactional(readOnly = true) + public SelectTeamsResponse selectAll() { + List teams = teamRepository.findAll(); + checkEmpty(teams); + return new SelectTeamsResponse(teams); + } + + private void checkEmpty(final List teams) { + if (teams.isEmpty()) { + throw new EntityNotFoundException("존재하는 팀이 없습니다."); + } } } diff --git a/src/main/java/playground/service/team/response/SelectTeamResponse.java b/src/main/java/playground/service/team/response/SelectTeamResponse.java new file mode 100644 index 0000000..c9bf101 --- /dev/null +++ b/src/main/java/playground/service/team/response/SelectTeamResponse.java @@ -0,0 +1,19 @@ +package playground.service.team.response; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import playground.domain.team.Team; + +@Getter +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class SelectTeamResponse { + + private Long id; + private String name; + + public SelectTeamResponse(final Team team) { + this.id = team.getId(); + this.name = team.getName(); + } +} diff --git a/src/main/java/playground/service/team/response/SelectTeamsResponse.java b/src/main/java/playground/service/team/response/SelectTeamsResponse.java new file mode 100644 index 0000000..67d5707 --- /dev/null +++ b/src/main/java/playground/service/team/response/SelectTeamsResponse.java @@ -0,0 +1,23 @@ +package playground.service.team.response; + + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import playground.domain.team.Team; + +import java.util.List; +import java.util.stream.Collectors; + +@Getter +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class SelectTeamsResponse { + + private List selectTeamResponses; + + public SelectTeamsResponse(final List teams) { + this.selectTeamResponses = teams.stream() + .map(SelectTeamResponse::new) + .collect(Collectors.toList()); + } +} diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index 77e0c96..07b6927 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -1,5 +1,11 @@ -insert into user(user_id, email, password, name) -values (1, 'wbluke@gmail.com', '1234', '박우빈'); +insert into team(team_id, name) +values (1, '운영팀'); -insert into user(user_id, email, password, name) -values (2, 'wbluke2@gmail.com', '1234', '닉우빈'); +insert into team(team_id, name) +values (2, 'CS팀'); + +insert into user(user_id, email, password, name, team_id) +values (1, 'wbluke@gmail.com', '1234', '박우빈', 1); + +insert into user(user_id, email, password, name, team_id) +values (2, 'wbluke2@gmail.com', '1234', '닉우빈', 2); diff --git a/src/test/java/playground/controller/team/TeamControllerTest.java b/src/test/java/playground/controller/team/TeamControllerTest.java index eaf81b0..295a3c3 100644 --- a/src/test/java/playground/controller/team/TeamControllerTest.java +++ b/src/test/java/playground/controller/team/TeamControllerTest.java @@ -13,6 +13,7 @@ import playground.service.team.TeamService; import playground.service.team.request.CreateTeamRequest; +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.MockMvcResultMatchers.status; @@ -54,4 +55,12 @@ void create_fail_empty_name(String invalidName) throws Exception { .content(objectMapper.writeValueAsString(createTeamRequest))) .andExpect(status().isBadRequest()); } + + @Test + @DisplayName("모든 팀을 조회한다.") + void selectAll() throws Exception { + mockMvc.perform(get("/api/teams") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + } } diff --git a/src/test/java/playground/repository/document/DocumentRepositoryTest.java b/src/test/java/playground/repository/document/DocumentRepositoryTest.java index 4311597..14df1ce 100644 --- a/src/test/java/playground/repository/document/DocumentRepositoryTest.java +++ b/src/test/java/playground/repository/document/DocumentRepositoryTest.java @@ -64,7 +64,6 @@ void findByIdWithDrafter() { assertThat(persistenceUnitUtil.isLoaded(fetchedDocument.get().getDrafter())).isTrue(); } - @Test @DisplayName("기안자의 정보가 포함된 조건에 맞는 모든 문서를 조회한다.") void findAllWithDrafter() { diff --git a/src/test/java/playground/service/team/TeamServiceTest.java b/src/test/java/playground/service/team/TeamServiceTest.java index ede968d..275ef08 100644 --- a/src/test/java/playground/service/team/TeamServiceTest.java +++ b/src/test/java/playground/service/team/TeamServiceTest.java @@ -6,14 +6,19 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.dao.DuplicateKeyException; import playground.domain.team.Team; import playground.repository.team.TeamRepository; import playground.service.team.request.CreateTeamRequest; +import playground.service.team.response.SelectTeamsResponse; import javax.persistence.EntityNotFoundException; +import java.util.Arrays; +import java.util.Collections; import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; @@ -69,4 +74,44 @@ void save() { //then verify(teamRepository, times(1)).save(any(Team.class)); } + + @Test + @DisplayName("중복된 팀 명으로 저장할경우, 예외가 발생한다.") + void save_fail_duplicated_name() { + //given + CreateTeamRequest createTeamRequest = new CreateTeamRequest("정산시스템팀"); + given(teamRepository.save(any(Team.class))).willThrow(new DuplicateKeyException("이름 중복")); + + //when, then + assertThatIllegalArgumentException() + .isThrownBy(() -> teamService.save(createTeamRequest)) + .withMessageContaining("이미 존재하는 팀입니다."); + } + + @Test + @DisplayName("모든 팀을 조회한다.") + void selectAll() { + //given + Team team1 = new Team("정산시스템팀"); + Team team2 = new Team("서비스개발팀"); + given(teamRepository.findAll()).willReturn(Arrays.asList(team1, team2)); + + //when + SelectTeamsResponse selectTeamsResponse = teamService.selectAll(); + + //then + assertThat(selectTeamsResponse).isNotNull(); + } + + @Test + @DisplayName("존재하는 팀이 없을 경우, 예외가 발생한다.") + void selectAll_return_empty() { + //given + given(teamRepository.findAll()).willReturn(Collections.emptyList()); + + //when, then + assertThatThrownBy(() -> teamService.selectAll()) + .isInstanceOf(EntityNotFoundException.class) + .hasMessageContaining("존재하는 팀이 없습니다."); + } } From 0153cc05cc5ced45083ef83abd9cdf46ce5b7c85 Mon Sep 17 00:00:00 2001 From: Beenie93 Date: Sat, 4 Dec 2021 00:58:15 +0900 Subject: [PATCH 08/14] =?UTF-8?q?feat=20:=20=EC=97=AD=ED=95=A0=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EB=B0=8F=20=ED=8C=80=EC=97=90=20=EC=86=8D=ED=95=9C?= =?UTF-8?q?=20=ED=9A=8C=EC=9B=90=20=EC=A1=B0=ED=9A=8C=20API=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Beenie93 --- .../controller/user/UserController.java | 9 +++ .../java/playground/domain/user/User.java | 13 +++- .../domain/user/vo/JobPosition.java | 15 +++++ .../playground/service/team/TeamService.java | 6 ++ .../playground/service/user/UserService.java | 7 +++ .../user/request/CreateUserRequest.java | 10 +++- .../user/response/SelectUserResponse.java | 26 ++++++++ .../response/SelectUsersInTeamResponse.java | 22 +++++++ src/main/resources/data.sql | 14 +++-- .../controller/user/UserControllerTest.java | 39 ++++++++++-- .../domain/document/DocumentApprovalTest.java | 19 +++++- .../document/DocumentApprovalsTest.java | 59 ++++++++++++++++--- .../domain/document/DocumentTest.java | 9 ++- .../java/playground/domain/user/UserTest.java | 9 ++- .../document/DocumentRepositoryTest.java | 17 +++++- .../service/team/TeamServiceTest.java | 28 +++++++++ .../service/user/UserServiceTest.java | 17 +++--- 17 files changed, 287 insertions(+), 32 deletions(-) create mode 100644 src/main/java/playground/domain/user/vo/JobPosition.java create mode 100644 src/main/java/playground/service/user/response/SelectUserResponse.java create mode 100644 src/main/java/playground/service/user/response/SelectUsersInTeamResponse.java diff --git a/src/main/java/playground/controller/user/UserController.java b/src/main/java/playground/controller/user/UserController.java index 3447a74..63e93d6 100644 --- a/src/main/java/playground/controller/user/UserController.java +++ b/src/main/java/playground/controller/user/UserController.java @@ -2,12 +2,15 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import playground.service.user.UserService; import playground.service.user.request.CreateUserRequest; +import playground.service.user.response.SelectUsersInTeamResponse; import javax.validation.Valid; @@ -26,4 +29,10 @@ public ResponseEntity create(@RequestBody @Valid final CreateUserRequest c userService.save(createUserRequest); return new ResponseEntity<>(HttpStatus.CREATED); } + + @GetMapping() + public ResponseEntity selectUsersInTeam(@RequestParam final Long teamId) { + SelectUsersInTeamResponse selectUsersInTeamResponse = userService.selectUsersInTeam(teamId); + return ResponseEntity.ok(selectUsersInTeamResponse); + } } diff --git a/src/main/java/playground/domain/user/User.java b/src/main/java/playground/domain/user/User.java index 69d1934..4ac6819 100644 --- a/src/main/java/playground/domain/user/User.java +++ b/src/main/java/playground/domain/user/User.java @@ -1,13 +1,17 @@ package playground.domain.user; import lombok.AccessLevel; +import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; import playground.domain.team.Team; +import playground.domain.user.vo.JobPosition; import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; @@ -44,12 +48,19 @@ public class User { @JoinColumn(name = "team_id") private Team team; - public User(final String email, final String password, final String name, final Team team) { + @Enumerated(EnumType.STRING) + @Column(name = "job_position", nullable = false) + private JobPosition jobPosition; + + @Builder + public User(final String email, final String password, final String name, + final Team team, final JobPosition jobPosition) { this.email = email; this.password = password; this.name = name; this.team = team; this.team.addUser(this); + this.jobPosition = jobPosition; } } diff --git a/src/main/java/playground/domain/user/vo/JobPosition.java b/src/main/java/playground/domain/user/vo/JobPosition.java new file mode 100644 index 0000000..e519b06 --- /dev/null +++ b/src/main/java/playground/domain/user/vo/JobPosition.java @@ -0,0 +1,15 @@ +package playground.domain.user.vo; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum JobPosition { + + TEAM_LEADER("팀장"), + PART_MANAGER("파트장"), + TEAM_MEMBER("팀원"); + + private final String text; +} diff --git a/src/main/java/playground/service/team/TeamService.java b/src/main/java/playground/service/team/TeamService.java index e5b9f6d..787280e 100644 --- a/src/main/java/playground/service/team/TeamService.java +++ b/src/main/java/playground/service/team/TeamService.java @@ -52,4 +52,10 @@ private void checkEmpty(final List teams) { throw new EntityNotFoundException("존재하는 팀이 없습니다."); } } + + @Transactional(readOnly = true) + public Team findById(final Long teamId) { + return teamRepository.findById(teamId) + .orElseThrow(() -> new EntityNotFoundException(String.format("[%d] 식별번호에 해당하는 팀이 존재하지 않습니다.", teamId))); + } } diff --git a/src/main/java/playground/service/user/UserService.java b/src/main/java/playground/service/user/UserService.java index aa93fb8..1da2122 100644 --- a/src/main/java/playground/service/user/UserService.java +++ b/src/main/java/playground/service/user/UserService.java @@ -8,6 +8,7 @@ import playground.repository.user.UserRepository; import playground.service.team.TeamService; import playground.service.user.request.CreateUserRequest; +import playground.service.user.response.SelectUsersInTeamResponse; import javax.persistence.EntityNotFoundException; import java.util.List; @@ -57,4 +58,10 @@ public User findById(final Long userId) { return userRepository.findById(userId) .orElseThrow(() -> new EntityNotFoundException(String.format("[%d] 식별번호에 해당하는 회원이 존재하지 않습니다.", userId))); } + + @Transactional(readOnly = true) + public SelectUsersInTeamResponse selectUsersInTeam(final Long teamId) { + Team team = teamService.findById(teamId); + return new SelectUsersInTeamResponse(team.getUsers()); + } } diff --git a/src/main/java/playground/service/user/request/CreateUserRequest.java b/src/main/java/playground/service/user/request/CreateUserRequest.java index bb30aef..8c01c8b 100644 --- a/src/main/java/playground/service/user/request/CreateUserRequest.java +++ b/src/main/java/playground/service/user/request/CreateUserRequest.java @@ -5,6 +5,7 @@ import lombok.NoArgsConstructor; import playground.domain.team.Team; import playground.domain.user.User; +import playground.domain.user.vo.JobPosition; import javax.validation.constraints.Email; import javax.validation.constraints.NotBlank; @@ -26,14 +27,19 @@ public class CreateUserRequest { @NotBlank private String teamName; - public CreateUserRequest(final String email, final String password, final String name, final String teamName) { + @NotBlank + private String jobPosition; + + public CreateUserRequest(final String email, final String password, final String name, + final String teamName, final String jobPosition) { this.email = email; this.password = password; this.name = name; this.teamName = teamName; + this.jobPosition = jobPosition; } public User toUser(final Team team) { - return new User(email, password, name, team); + return new User(email, password, name, team, JobPosition.valueOf(jobPosition)); } } diff --git a/src/main/java/playground/service/user/response/SelectUserResponse.java b/src/main/java/playground/service/user/response/SelectUserResponse.java new file mode 100644 index 0000000..3cc2c2c --- /dev/null +++ b/src/main/java/playground/service/user/response/SelectUserResponse.java @@ -0,0 +1,26 @@ +package playground.service.user.response; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import playground.domain.user.User; +import playground.domain.user.vo.JobPosition; + +@Getter +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class SelectUserResponse { + + private Long id; + private JobPosition jobPosition; + private String teamName; + private String name; + private String jobPositionText; + + public SelectUserResponse(final User user) { + this.id = user.getId(); + this.jobPosition = user.getJobPosition(); + this.teamName = user.getTeam().getName(); + this.name = user.getName(); + this.jobPositionText = user.getJobPosition().getText(); + } +} diff --git a/src/main/java/playground/service/user/response/SelectUsersInTeamResponse.java b/src/main/java/playground/service/user/response/SelectUsersInTeamResponse.java new file mode 100644 index 0000000..cf137b1 --- /dev/null +++ b/src/main/java/playground/service/user/response/SelectUsersInTeamResponse.java @@ -0,0 +1,22 @@ +package playground.service.user.response; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import playground.domain.user.User; + +import java.util.List; +import java.util.stream.Collectors; + +@Getter +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class SelectUsersInTeamResponse { + + private List selectUserResponses; + + public SelectUsersInTeamResponse(final List users) { + this.selectUserResponses = users.stream() + .map(SelectUserResponse::new) + .collect(Collectors.toList()); + } +} diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index 07b6927..5f6e7c8 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -4,8 +4,14 @@ values (1, '운영팀'); insert into team(team_id, name) values (2, 'CS팀'); -insert into user(user_id, email, password, name, team_id) -values (1, 'wbluke@gmail.com', '1234', '박우빈', 1); +insert into user(user_id, email, password, name, team_id, job_position) +values (1, 'wbluke@gmail.com', '1234', '박우빈1', 1, 'TEAM_MEMBER'); -insert into user(user_id, email, password, name, team_id) -values (2, 'wbluke2@gmail.com', '1234', '닉우빈', 2); +insert into user(user_id, email, password, name, team_id, job_position) +values (2, 'wbluke2@gmail.com', '1234', '박우빈2', 2, 'TEAM_MEMBER'); + +insert into user(user_id, email, password, name, team_id, job_position) +values (3, 'wbluke3@gmail.com', '1234', '박우빈3', 1, 'TEAM_MEMBER'); + +insert into user(user_id, email, password, name, team_id, job_position) +values (4, 'wbluke4@gmail.com', '1234', '박우빈4', 2, 'TEAM_MEMBER'); diff --git a/src/test/java/playground/controller/user/UserControllerTest.java b/src/test/java/playground/controller/user/UserControllerTest.java index 16d9562..0f56bd6 100644 --- a/src/test/java/playground/controller/user/UserControllerTest.java +++ b/src/test/java/playground/controller/user/UserControllerTest.java @@ -8,11 +8,21 @@ import org.mockito.Mock; import org.springframework.http.MediaType; import playground.common.AbstractControllerTest; +import playground.domain.team.Team; +import playground.domain.user.User; import playground.service.user.UserService; import playground.service.user.request.CreateUserRequest; +import playground.service.user.response.SelectUsersInTeamResponse; +import java.util.Collections; + +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +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.MockMvcResultMatchers.status; +import static playground.domain.user.vo.JobPosition.TEAM_MEMBER; public class UserControllerTest extends AbstractControllerTest { @@ -27,7 +37,7 @@ protected Object setController() { @Test @DisplayName("사용자 생성 요청을 받아 사용자를 생성 후, HTTP 201을 반환한다.") void create() throws Exception { - CreateUserRequest createUserRequest = new CreateUserRequest("seongbeen93@naver.com", "password", "김성빈", "정산시스템팀"); + CreateUserRequest createUserRequest = new CreateUserRequest("seongbeen93@naver.com", "password", "김성빈", "정산시스템팀", TEAM_MEMBER.getText()); mockMvc.perform(post("/api/users") .accept(MediaType.APPLICATION_JSON) @@ -40,7 +50,7 @@ void create() throws Exception { @ValueSource(strings = {"idnaver.com", "", "@naver.com"}) @DisplayName("이메일 형식이 올바르지 않을 경우, 예외가 발생한다.") void create_fail_invalid_email(String invalidEmail) throws Exception { - CreateUserRequest createUserRequest = new CreateUserRequest(invalidEmail, "password", "김성빈", "정산시스템팀"); + CreateUserRequest createUserRequest = new CreateUserRequest(invalidEmail, "password", "김성빈", "정산시스템팀", TEAM_MEMBER.getText()); mockMvc.perform(post("/api/users") .accept(MediaType.APPLICATION_JSON) @@ -53,7 +63,7 @@ void create_fail_invalid_email(String invalidEmail) throws Exception { @NullAndEmptySource @DisplayName("비밀번호가 공백 또는 null있을 경우, 예외가 발생한다.") void create_fail_empty_password(String invalidPassword) throws Exception { - CreateUserRequest createUserRequest = new CreateUserRequest("seongbeen93@naver.com", invalidPassword, "김성빈", "정산시스템팀"); + CreateUserRequest createUserRequest = new CreateUserRequest("seongbeen93@naver.com", invalidPassword, "김성빈", "정산시스템팀", TEAM_MEMBER.getText()); mockMvc.perform(post("/api/users") .accept(MediaType.APPLICATION_JSON) @@ -66,7 +76,7 @@ void create_fail_empty_password(String invalidPassword) throws Exception { @NullAndEmptySource @DisplayName("이름이 공백 또는 null일 경우, 예외가 발생한다.") void create_fail_empty_name(String invalidName) throws Exception { - CreateUserRequest createUserRequest = new CreateUserRequest("seongbeen93@naver.com", "password", invalidName, "정산시스템팀"); + CreateUserRequest createUserRequest = new CreateUserRequest("seongbeen93@naver.com", "password", invalidName, "정산시스템팀", TEAM_MEMBER.getText()); mockMvc.perform(post("/api/users") .accept(MediaType.APPLICATION_JSON) @@ -79,7 +89,7 @@ void create_fail_empty_name(String invalidName) throws Exception { @NullAndEmptySource @DisplayName("팀명이 공백 또는 null일 경우, 예외가 발생한다.") void create_fail_empty_team(String invalidTeamName) throws Exception { - CreateUserRequest createUserRequest = new CreateUserRequest("seongbeen93@naver.com", "password", "김성빈", invalidTeamName); + CreateUserRequest createUserRequest = new CreateUserRequest("seongbeen93@naver.com", "password", "김성빈", invalidTeamName, TEAM_MEMBER.getText()); mockMvc.perform(post("/api/users") .accept(MediaType.APPLICATION_JSON) @@ -87,4 +97,23 @@ void create_fail_empty_team(String invalidTeamName) throws Exception { .content(objectMapper.writeValueAsString(createUserRequest))) .andExpect(status().isBadRequest()); } + + @Test + @DisplayName("특정 팀에 속한 사용자 조회 요청을 전달받아, 사용자들의 정보를 반환한다.") + void selectUsersInTeam() throws Exception { + User user = mock(User.class); + Team team = mock(Team.class); + given(user.getId()).willReturn(1L); + given(user.getName()).willReturn("김성빈"); + given(user.getJobPosition()).willReturn(TEAM_MEMBER); + given(user.getTeam()).willReturn(team); + given(team.getName()).willReturn("운영팀"); + SelectUsersInTeamResponse selectUsersInTeamResponse = new SelectUsersInTeamResponse(Collections.singletonList(user)); + given(userService.selectUsersInTeam(anyLong())).willReturn(selectUsersInTeamResponse); + + mockMvc.perform(get("/api/users") + .param("teamId", "1") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + } } diff --git a/src/test/java/playground/domain/document/DocumentApprovalTest.java b/src/test/java/playground/domain/document/DocumentApprovalTest.java index 8da8fd5..0da3893 100644 --- a/src/test/java/playground/domain/document/DocumentApprovalTest.java +++ b/src/test/java/playground/domain/document/DocumentApprovalTest.java @@ -6,6 +6,7 @@ import playground.domain.document.vo.Category; import playground.domain.team.Team; import playground.domain.user.User; +import playground.domain.user.vo.JobPosition; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -17,8 +18,22 @@ class DocumentApprovalTest { void create() { //given Team team = mock(Team.class); - User drafter = new User("test@naver.com", "Password123!", "drafter", team); - User approver = new User("test@naver.com", "Password123!", "approver", team); + User drafter = User.builder() + .email("test1@naver.com") + .password("Password123!") + .name("drafter") + .team(team) + .jobPosition(JobPosition.TEAM_MEMBER) + .build(); + + User approver = User.builder() + .email("test2@naver.com") + .password("Password123!") + .name("approver") + .team(team) + .jobPosition(JobPosition.TEAM_MEMBER) + .build(); + Document document = Document.builder() .drafter(drafter) .category(Category.EDUCATION) diff --git a/src/test/java/playground/domain/document/DocumentApprovalsTest.java b/src/test/java/playground/domain/document/DocumentApprovalsTest.java index 66889cd..bc9257c 100644 --- a/src/test/java/playground/domain/document/DocumentApprovalsTest.java +++ b/src/test/java/playground/domain/document/DocumentApprovalsTest.java @@ -5,6 +5,7 @@ import playground.domain.document.vo.Category; import playground.domain.team.Team; import playground.domain.user.User; +import playground.domain.user.vo.JobPosition; import java.util.Arrays; import java.util.Collections; @@ -20,9 +21,29 @@ class DocumentApprovalsTest { void enroll() { //given Team team = mock(Team.class); - User drafter = new User("test1@naver.com", "Password123!", "drafter", team); - User approver1 = new User("test2@naver.com", "Password123!", "approver1", team); - User approver2 = new User("test3@naver.com", "Password123!", "approver2", team); + User drafter = User.builder() + .email("test1@naver.com") + .password("Password123!") + .name("drafter") + .team(team) + .jobPosition(JobPosition.TEAM_MEMBER) + .build(); + + User approver1 = User.builder() + .email("test2@naver.com") + .password("Password123!") + .name("approver1") + .team(team) + .jobPosition(JobPosition.TEAM_MEMBER) + .build(); + + User approver2 = User.builder() + .email("test2@naver.com") + .password("Password123!") + .name("approver2") + .team(team) + .jobPosition(JobPosition.TEAM_MEMBER) + .build(); Document document = Document.builder() .drafter(drafter) @@ -45,9 +66,27 @@ void enroll() { void enroll_fail() { //given Team team = mock(Team.class); - User drafter = new User("test1@naver.com", "Password123!", "drafter", team); - User approver1 = new User("test2@naver.com", "Password123!", "approver1", team); - User approver2 = new User("test3@naver.com", "Password123!", "approver2", team); + User drafter = User.builder() + .email("test1@naver.com") + .password("Password123!") + .name("drafter") + .team(team) + .jobPosition(JobPosition.TEAM_MEMBER) + .build(); + User approver1 = User.builder() + .email("test2@naver.com") + .password("Password123!") + .name("approver1") + .team(team) + .jobPosition(JobPosition.TEAM_MEMBER) + .build(); + User approver2 = User.builder() + .email("test2@naver.com") + .password("Password123!") + .name("approver2") + .team(team) + .jobPosition(JobPosition.TEAM_MEMBER) + .build(); Document document = Document.builder() .drafter(drafter) @@ -58,7 +97,13 @@ void enroll_fail() { DocumentApprovals documentApprovals = new DocumentApprovals(); documentApprovals.enroll(Arrays.asList(approver1, approver2), document); - User approver3 = new User("test4@naver.com", "Password123!", "approver3", team); + User approver3 = User.builder() + .email("test4@naver.com") + .password("Password123!") + .name("approver3") + .team(team) + .jobPosition(JobPosition.TEAM_MEMBER) + .build(); //when, then assertThatIllegalStateException() diff --git a/src/test/java/playground/domain/document/DocumentTest.java b/src/test/java/playground/domain/document/DocumentTest.java index fd6fb2b..5c34154 100644 --- a/src/test/java/playground/domain/document/DocumentTest.java +++ b/src/test/java/playground/domain/document/DocumentTest.java @@ -6,6 +6,7 @@ import playground.domain.document.vo.Category; import playground.domain.team.Team; import playground.domain.user.User; +import playground.domain.user.vo.JobPosition; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -20,7 +21,13 @@ void create() { Category category = Category.EDUCATION; String contents = "교육비"; Team team = mock(Team.class); - User drafter = new User("test@naver.com", "Password123!", "drafter", team); + User drafter = User.builder() + .email("test@naver.com") + .password("Password123!") + .name("drafter") + .team(team) + .jobPosition(JobPosition.TEAM_MEMBER) + .build(); //when Document document = Document.builder() diff --git a/src/test/java/playground/domain/user/UserTest.java b/src/test/java/playground/domain/user/UserTest.java index c04053b..748ebf8 100644 --- a/src/test/java/playground/domain/user/UserTest.java +++ b/src/test/java/playground/domain/user/UserTest.java @@ -3,6 +3,7 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import playground.domain.team.Team; +import playground.domain.user.vo.JobPosition; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -19,7 +20,13 @@ void create() { String name = "김성빈"; //when - User user = new User(email, password, name, team); + User user = User.builder() + .email(email) + .password(password) + .name(name) + .team(team) + .jobPosition(JobPosition.TEAM_MEMBER) + .build(); //then assertThat(user) diff --git a/src/test/java/playground/repository/document/DocumentRepositoryTest.java b/src/test/java/playground/repository/document/DocumentRepositoryTest.java index 14df1ce..202c0a1 100644 --- a/src/test/java/playground/repository/document/DocumentRepositoryTest.java +++ b/src/test/java/playground/repository/document/DocumentRepositoryTest.java @@ -10,6 +10,7 @@ import playground.domain.document.vo.Category; import playground.domain.team.Team; import playground.domain.user.User; +import playground.domain.user.vo.JobPosition; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; @@ -44,7 +45,13 @@ void findByIdWithDrafter() { //given Team team = new Team("정산시스템팀"); entityManager.persist(team); - User drafter = new User("test@naver.com", "Password123!", "drafter", team); + User drafter = User.builder() + .email("test@naver.com") + .password("Password123!") + .name("drafter") + .team(team) + .jobPosition(JobPosition.TEAM_MEMBER) + .build(); entityManager.persist(drafter); Document document = Document.builder() .drafter(drafter) @@ -70,7 +77,13 @@ void findAllWithDrafter() { //given Team team = new Team("정산시스템팀"); entityManager.persist(team); - User drafter = new User("test@naver.com", "Password123!", "drafter", team); + User drafter = User.builder() + .email("test@naver.com") + .password("Password123!") + .name("drafter") + .team(team) + .jobPosition(JobPosition.TEAM_MEMBER) + .build(); entityManager.persist(drafter); Document document = Document.builder() .drafter(drafter) diff --git a/src/test/java/playground/service/team/TeamServiceTest.java b/src/test/java/playground/service/team/TeamServiceTest.java index 275ef08..2d49955 100644 --- a/src/test/java/playground/service/team/TeamServiceTest.java +++ b/src/test/java/playground/service/team/TeamServiceTest.java @@ -21,8 +21,10 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -114,4 +116,30 @@ void selectAll_return_empty() { .isInstanceOf(EntityNotFoundException.class) .hasMessageContaining("존재하는 팀이 없습니다."); } + + @Test + @DisplayName("식별번호에 일치하는 팀을 조회한다.") + void findById() { + //given + Team mockTeam = mock(Team.class); + given(teamRepository.findById(anyLong())).willReturn(Optional.of(mockTeam)); + + //when + Team team = teamService.findById(1L); + + //then + assertThat(team).isNotNull(); + } + + @Test + @DisplayName("식별번호에 일치하는 팀이 존재하지 않을 경우, 예외가 발생한다.") + void findById_fail_not_found_team() { + //given + given(teamRepository.findById(anyLong())).willReturn(Optional.empty()); + + //when, then + assertThatThrownBy(() -> teamService.findById(1L)) + .isInstanceOf(EntityNotFoundException.class) + .hasMessageContaining("해당하는 팀이 존재하지 않습니다"); + } } diff --git a/src/test/java/playground/service/user/UserServiceTest.java b/src/test/java/playground/service/user/UserServiceTest.java index f3df827..bc3d60d 100644 --- a/src/test/java/playground/service/user/UserServiceTest.java +++ b/src/test/java/playground/service/user/UserServiceTest.java @@ -13,12 +13,14 @@ import playground.service.team.TeamService; import playground.service.user.request.CreateUserRequest; +import javax.persistence.EntityNotFoundException; import java.util.Collections; import java.util.List; import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.anyLong; @@ -27,6 +29,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static playground.domain.user.vo.JobPosition.TEAM_MEMBER; @ExtendWith(MockitoExtension.class) class UserServiceTest { @@ -46,7 +49,7 @@ void save() { //given Team team = mock(Team.class); given(teamService.findByName(anyString())).willReturn(team); - CreateUserRequest createUserRequest = new CreateUserRequest("a@naver.com", "Password123!", "김성빈", "정산시스템팀"); + CreateUserRequest createUserRequest = new CreateUserRequest("a@naver.com", "Password123!", "김성빈", "정산시스템팀", TEAM_MEMBER.name()); //when userService.save(createUserRequest); @@ -62,7 +65,7 @@ void save_fail_duplicated_email() { Team team = mock(Team.class); given(teamService.findByName(anyString())).willReturn(team); given(userRepository.save(any(User.class))).willThrow(new DuplicateKeyException("이메일 중복")); - CreateUserRequest createUserRequest = new CreateUserRequest("a@naver.com", "Password123!", "김성빈", "정산시스템팀"); + CreateUserRequest createUserRequest = new CreateUserRequest("a@naver.com", "Password123!", "김성빈", "정산시스템팀", TEAM_MEMBER.name()); //when, then assertThatIllegalArgumentException() @@ -77,7 +80,7 @@ void save_fail_team_not_found() { Team team = mock(Team.class); given(teamService.findByName(anyString())).willReturn(team); given(userRepository.save(any(User.class))).willThrow(new DuplicateKeyException("이메일 중복")); - CreateUserRequest createUserRequest = new CreateUserRequest("a@naver.com", "Password123!", "김성빈", "정산시스템팀"); + CreateUserRequest createUserRequest = new CreateUserRequest("a@naver.com", "Password123!", "김성빈", "정산시스템팀", TEAM_MEMBER.name()); //when, then assertThatIllegalArgumentException() @@ -117,11 +120,11 @@ void findById() { @DisplayName("식별번호에 일치하는 사용자가 존재하지 않을 경우, 예외가 발생한다.") void findById_fail_not_found_user() { //given - given(userRepository.findById(anyLong())).willThrow(new IllegalArgumentException("해당하는 회원이 존재하지 않습니다")); + given(userRepository.findById(anyLong())).willReturn(Optional.empty()); //when, then - assertThatIllegalArgumentException() - .isThrownBy(() -> userService.findById(1L)) - .withMessageContaining("해당하는 회원이 존재하지 않습니다"); + assertThatThrownBy(() -> userService.findById(1L)) + .isInstanceOf(EntityNotFoundException.class) + .hasMessageContaining("해당하는 회원이 존재하지 않습니다"); } } From 609e25b8ec3785e12f873af1073372cc9d1bffb1 Mon Sep 17 00:00:00 2001 From: Beenie93 Date: Sat, 4 Dec 2021 01:21:42 +0900 Subject: [PATCH 09/14] =?UTF-8?q?refactor=20:=20=ED=95=A8=EC=88=98=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=ED=86=B5=EC=9D=BC=20select=20->=20find,?= =?UTF-8?q?=20save=20->=20create=20=EB=B0=8F=20=EB=AA=85=ED=99=95=ED=95=9C?= =?UTF-8?q?=20=EC=9D=B4=EB=A6=84=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Beenie93 --- .../document/DocumentController.java | 10 +++---- .../controller/team/TeamController.java | 6 ++-- .../controller/user/UserController.java | 10 +++---- .../document/DocumentRepository.java | 4 +-- .../service/document/DocumentService.java | 18 +++++------ .../playground/service/team/TeamService.java | 4 +-- .../playground/service/user/UserService.java | 8 ++--- ....java => SelectAllUserInTeamResponse.java} | 4 +-- .../document/DocumentControllerTest.java | 4 +-- .../controller/team/TeamControllerTest.java | 2 +- .../controller/user/UserControllerTest.java | 8 ++--- .../document/DocumentRepositoryTest.java | 8 ++--- .../service/document/DocumentServiceTest.java | 30 +++++++++---------- .../service/team/TeamServiceTest.java | 16 +++++----- .../service/user/UserServiceTest.java | 6 ++-- 15 files changed, 69 insertions(+), 69 deletions(-) rename src/main/java/playground/service/user/response/{SelectUsersInTeamResponse.java => SelectAllUserInTeamResponse.java} (81%) diff --git a/src/main/java/playground/controller/document/DocumentController.java b/src/main/java/playground/controller/document/DocumentController.java index f959733..746e737 100644 --- a/src/main/java/playground/controller/document/DocumentController.java +++ b/src/main/java/playground/controller/document/DocumentController.java @@ -29,19 +29,19 @@ public DocumentController(final DocumentService documentService) { @PostMapping public ResponseEntity create(@RequestBody @Valid final CreateDocumentRequest createDocumentRequest) { - documentService.save(createDocumentRequest); + documentService.create(createDocumentRequest); return new ResponseEntity<>(HttpStatus.CREATED); } @GetMapping("/{documentId}") - public ResponseEntity select(final @PathVariable Long documentId) { - SelectDocumentResponse selectDocumentResponse = documentService.select(documentId); + public ResponseEntity find(final @PathVariable Long documentId) { + SelectDocumentResponse selectDocumentResponse = documentService.find(documentId); return ResponseEntity.ok(selectDocumentResponse); } @GetMapping("/outbox") - public ResponseEntity> selectOutBox(final @RequestParam Long drafterId) { - List selectMultiOutBoxResponse = documentService.selectOutBox(drafterId); + public ResponseEntity> findOutBox(final @RequestParam Long drafterId) { + List selectMultiOutBoxResponse = documentService.findOutBox(drafterId); return ResponseEntity.ok(selectMultiOutBoxResponse); } } diff --git a/src/main/java/playground/controller/team/TeamController.java b/src/main/java/playground/controller/team/TeamController.java index a9488e2..3719a2e 100644 --- a/src/main/java/playground/controller/team/TeamController.java +++ b/src/main/java/playground/controller/team/TeamController.java @@ -25,13 +25,13 @@ public TeamController(final TeamService teamService) { @PostMapping public ResponseEntity create(@RequestBody @Valid final CreateTeamRequest createTeamRequest) { - teamService.save(createTeamRequest); + teamService.create(createTeamRequest); return new ResponseEntity<>(HttpStatus.CREATED); } @GetMapping - public ResponseEntity selectAll() { - SelectTeamsResponse selectTeamsResponse = teamService.selectAll(); + public ResponseEntity findAll() { + SelectTeamsResponse selectTeamsResponse = teamService.findAll(); return ResponseEntity.ok(selectTeamsResponse); } } diff --git a/src/main/java/playground/controller/user/UserController.java b/src/main/java/playground/controller/user/UserController.java index 63e93d6..46ab16e 100644 --- a/src/main/java/playground/controller/user/UserController.java +++ b/src/main/java/playground/controller/user/UserController.java @@ -10,7 +10,7 @@ import org.springframework.web.bind.annotation.RestController; import playground.service.user.UserService; import playground.service.user.request.CreateUserRequest; -import playground.service.user.response.SelectUsersInTeamResponse; +import playground.service.user.response.SelectAllUserInTeamResponse; import javax.validation.Valid; @@ -26,13 +26,13 @@ public UserController(final UserService userService) { @PostMapping public ResponseEntity create(@RequestBody @Valid final CreateUserRequest createUserRequest) { - userService.save(createUserRequest); + userService.create(createUserRequest); return new ResponseEntity<>(HttpStatus.CREATED); } @GetMapping() - public ResponseEntity selectUsersInTeam(@RequestParam final Long teamId) { - SelectUsersInTeamResponse selectUsersInTeamResponse = userService.selectUsersInTeam(teamId); - return ResponseEntity.ok(selectUsersInTeamResponse); + public ResponseEntity findAllUserInTeam(@RequestParam final Long teamId) { + SelectAllUserInTeamResponse selectAllUserInTeamResponse = userService.findAllUserInTeam(teamId); + return ResponseEntity.ok(selectAllUserInTeamResponse); } } diff --git a/src/main/java/playground/repository/document/DocumentRepository.java b/src/main/java/playground/repository/document/DocumentRepository.java index 2cff4a9..f1e36d5 100644 --- a/src/main/java/playground/repository/document/DocumentRepository.java +++ b/src/main/java/playground/repository/document/DocumentRepository.java @@ -12,8 +12,8 @@ public interface DocumentRepository extends JpaRepository { @Query("select d from Document d join fetch d.drafter where d.id = :document_id") - Optional findByIdWithDrafter(@Param("document_id") final Long documentId); + Optional findDocumentAndDrafterById(@Param("document_id") final Long documentId); @Query("select d from Document d join fetch d.drafter where d.drafter.id = :drafter_id and d.approvalState = :approval_state") - List findAllWithDrafter(@Param("drafter_id") final Long drafterId, @Param("approval_state") final ApprovalState approvalState); + List findAllDocumentAndDrafterByDrafterIdAndApprovalState(@Param("drafter_id") final Long drafterId, @Param("approval_state") final ApprovalState approvalState); } diff --git a/src/main/java/playground/service/document/DocumentService.java b/src/main/java/playground/service/document/DocumentService.java index 6c9c02d..e44a4d9 100644 --- a/src/main/java/playground/service/document/DocumentService.java +++ b/src/main/java/playground/service/document/DocumentService.java @@ -28,14 +28,14 @@ public DocumentService(final DocumentRepository documentRepository, } @Transactional - public void save(final CreateDocumentRequest createDocumentRequest) { + public void create(final CreateDocumentRequest createDocumentRequest) { List approverIds = createDocumentRequest.getApproverIds(); checkApprovalExistence(approverIds); Long drafterId = createDocumentRequest.getDrafterId(); User drafter = userService.findById(drafterId); Document document = createDocumentRequest.toDocument(drafter); - List approvers = findAllById(approverIds); + List approvers = findAllUserById(approverIds); document.enrollApprovals(approvers, document); documentRepository.save(document); } @@ -48,26 +48,26 @@ private void checkApprovalExistence(final List approvalIds) { } } - private List findAllById(final List approverIds) { + private List findAllUserById(final List approverIds) { return approverIds.stream() .map(userService::findById) .collect(Collectors.toList()); } @Transactional(readOnly = true) - public SelectDocumentResponse select(final Long documentId) { - Document document = findByIdWithDrafter(documentId); + public SelectDocumentResponse find(final Long documentId) { + Document document = findDocumentAndDrafterById(documentId); return new SelectDocumentResponse(document); } - private Document findByIdWithDrafter(final Long documentId) { - return documentRepository.findByIdWithDrafter(documentId) + private Document findDocumentAndDrafterById(final Long documentId) { + return documentRepository.findDocumentAndDrafterById(documentId) .orElseThrow(() -> new EntityNotFoundException(String.format("[%d] 식별번호에 해당하는 문서가 존재하지 않습니다.", documentId))); } @Transactional(readOnly = true) - public List selectOutBox(final Long drafterId) { - List documents = documentRepository.findAllWithDrafter(drafterId, ApprovalState.DRAFTING); + public List findOutBox(final Long drafterId) { + List documents = documentRepository.findAllDocumentAndDrafterByDrafterIdAndApprovalState(drafterId, ApprovalState.DRAFTING); checkEmpty(documents); return documents.stream() diff --git a/src/main/java/playground/service/team/TeamService.java b/src/main/java/playground/service/team/TeamService.java index 787280e..26b48f6 100644 --- a/src/main/java/playground/service/team/TeamService.java +++ b/src/main/java/playground/service/team/TeamService.java @@ -27,7 +27,7 @@ public Team findByName(final String teamName) { } @Transactional - public void save(final CreateTeamRequest createTeamRequest) { + public void create(final CreateTeamRequest createTeamRequest) { Team team = createTeamRequest.toTeam(); save(team); } @@ -41,7 +41,7 @@ private void save(final Team team) { } @Transactional(readOnly = true) - public SelectTeamsResponse selectAll() { + public SelectTeamsResponse findAll() { List teams = teamRepository.findAll(); checkEmpty(teams); return new SelectTeamsResponse(teams); diff --git a/src/main/java/playground/service/user/UserService.java b/src/main/java/playground/service/user/UserService.java index 1da2122..bb0ab8f 100644 --- a/src/main/java/playground/service/user/UserService.java +++ b/src/main/java/playground/service/user/UserService.java @@ -8,7 +8,7 @@ import playground.repository.user.UserRepository; import playground.service.team.TeamService; import playground.service.user.request.CreateUserRequest; -import playground.service.user.response.SelectUsersInTeamResponse; +import playground.service.user.response.SelectAllUserInTeamResponse; import javax.persistence.EntityNotFoundException; import java.util.List; @@ -25,7 +25,7 @@ public UserService(final UserRepository userRepository, final TeamService teamSe } @Transactional - public void save(final CreateUserRequest createUserRequest) { + public void create(final CreateUserRequest createUserRequest) { Team team = teamService.findByName(createUserRequest.getTeamName()); User user = createUserRequest.toUser(team); save(user); @@ -60,8 +60,8 @@ public User findById(final Long userId) { } @Transactional(readOnly = true) - public SelectUsersInTeamResponse selectUsersInTeam(final Long teamId) { + public SelectAllUserInTeamResponse findAllUserInTeam(final Long teamId) { Team team = teamService.findById(teamId); - return new SelectUsersInTeamResponse(team.getUsers()); + return new SelectAllUserInTeamResponse(team.getUsers()); } } diff --git a/src/main/java/playground/service/user/response/SelectUsersInTeamResponse.java b/src/main/java/playground/service/user/response/SelectAllUserInTeamResponse.java similarity index 81% rename from src/main/java/playground/service/user/response/SelectUsersInTeamResponse.java rename to src/main/java/playground/service/user/response/SelectAllUserInTeamResponse.java index cf137b1..62df78a 100644 --- a/src/main/java/playground/service/user/response/SelectUsersInTeamResponse.java +++ b/src/main/java/playground/service/user/response/SelectAllUserInTeamResponse.java @@ -10,11 +10,11 @@ @Getter @NoArgsConstructor(access = AccessLevel.PRIVATE) -public class SelectUsersInTeamResponse { +public class SelectAllUserInTeamResponse { private List selectUserResponses; - public SelectUsersInTeamResponse(final List users) { + public SelectAllUserInTeamResponse(final List users) { this.selectUserResponses = users.stream() .map(SelectUserResponse::new) .collect(Collectors.toList()); diff --git a/src/test/java/playground/controller/document/DocumentControllerTest.java b/src/test/java/playground/controller/document/DocumentControllerTest.java index aef7f16..1f8c55f 100644 --- a/src/test/java/playground/controller/document/DocumentControllerTest.java +++ b/src/test/java/playground/controller/document/DocumentControllerTest.java @@ -111,7 +111,7 @@ void create_fail_empty_approver_ids(List invalidApproverIds) throws Except @Test @DisplayName("문서를 조회한다.") - void select() throws Exception { + void find() throws Exception { mockMvc.perform(get("/api/documents/{documentId}", 1L) .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()); @@ -119,7 +119,7 @@ void select() throws Exception { @Test @DisplayName("Outbox 문서 리스트를 조회한다.") - void selectOutBox() throws Exception { + void findOutBox() throws Exception { mockMvc.perform(get("/api/documents/outbox") .param("drafterId", "1") .accept(MediaType.APPLICATION_JSON)) diff --git a/src/test/java/playground/controller/team/TeamControllerTest.java b/src/test/java/playground/controller/team/TeamControllerTest.java index 295a3c3..178c400 100644 --- a/src/test/java/playground/controller/team/TeamControllerTest.java +++ b/src/test/java/playground/controller/team/TeamControllerTest.java @@ -58,7 +58,7 @@ void create_fail_empty_name(String invalidName) throws Exception { @Test @DisplayName("모든 팀을 조회한다.") - void selectAll() throws Exception { + void findAll() throws Exception { mockMvc.perform(get("/api/teams") .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()); diff --git a/src/test/java/playground/controller/user/UserControllerTest.java b/src/test/java/playground/controller/user/UserControllerTest.java index 0f56bd6..ac32065 100644 --- a/src/test/java/playground/controller/user/UserControllerTest.java +++ b/src/test/java/playground/controller/user/UserControllerTest.java @@ -12,7 +12,7 @@ import playground.domain.user.User; import playground.service.user.UserService; import playground.service.user.request.CreateUserRequest; -import playground.service.user.response.SelectUsersInTeamResponse; +import playground.service.user.response.SelectAllUserInTeamResponse; import java.util.Collections; @@ -100,7 +100,7 @@ void create_fail_empty_team(String invalidTeamName) throws Exception { @Test @DisplayName("특정 팀에 속한 사용자 조회 요청을 전달받아, 사용자들의 정보를 반환한다.") - void selectUsersInTeam() throws Exception { + void findAllUserInTeam() throws Exception { User user = mock(User.class); Team team = mock(Team.class); given(user.getId()).willReturn(1L); @@ -108,8 +108,8 @@ void selectUsersInTeam() throws Exception { given(user.getJobPosition()).willReturn(TEAM_MEMBER); given(user.getTeam()).willReturn(team); given(team.getName()).willReturn("운영팀"); - SelectUsersInTeamResponse selectUsersInTeamResponse = new SelectUsersInTeamResponse(Collections.singletonList(user)); - given(userService.selectUsersInTeam(anyLong())).willReturn(selectUsersInTeamResponse); + SelectAllUserInTeamResponse selectAllUserInTeamResponse = new SelectAllUserInTeamResponse(Collections.singletonList(user)); + given(userService.findAllUserInTeam(anyLong())).willReturn(selectAllUserInTeamResponse); mockMvc.perform(get("/api/users") .param("teamId", "1") diff --git a/src/test/java/playground/repository/document/DocumentRepositoryTest.java b/src/test/java/playground/repository/document/DocumentRepositoryTest.java index 202c0a1..30d1f0e 100644 --- a/src/test/java/playground/repository/document/DocumentRepositoryTest.java +++ b/src/test/java/playground/repository/document/DocumentRepositoryTest.java @@ -41,7 +41,7 @@ void setUp() { @Test @DisplayName("기안자의 정보가 포함된 문서를 조회한다.") - void findByIdWithDrafter() { + void findDocumentAndDrafterById() { //given Team team = new Team("정산시스템팀"); entityManager.persist(team); @@ -64,7 +64,7 @@ void findByIdWithDrafter() { entityManager.clear(); //when - Optional fetchedDocument = documentRepository.findByIdWithDrafter(document.getId()); + Optional fetchedDocument = documentRepository.findDocumentAndDrafterById(document.getId()); //then assertThat(fetchedDocument).isNotEmpty(); @@ -73,7 +73,7 @@ void findByIdWithDrafter() { @Test @DisplayName("기안자의 정보가 포함된 조건에 맞는 모든 문서를 조회한다.") - void findAllWithDrafter() { + void findAllDocumentAndDrafterByDrafterIdAndApprovalState() { //given Team team = new Team("정산시스템팀"); entityManager.persist(team); @@ -96,7 +96,7 @@ void findAllWithDrafter() { entityManager.clear(); //when - List documents = documentRepository.findAllWithDrafter(drafter.getId(), ApprovalState.DRAFTING); + List documents = documentRepository.findAllDocumentAndDrafterByDrafterIdAndApprovalState(drafter.getId(), ApprovalState.DRAFTING); //then assertThat(documents).hasSize(1); diff --git a/src/test/java/playground/service/document/DocumentServiceTest.java b/src/test/java/playground/service/document/DocumentServiceTest.java index 7e75a9a..dd6076c 100644 --- a/src/test/java/playground/service/document/DocumentServiceTest.java +++ b/src/test/java/playground/service/document/DocumentServiceTest.java @@ -47,7 +47,7 @@ class DocumentServiceTest { @Test @DisplayName("문서를 저장한다.") - void save() { + void create() { //given User user = mock(User.class); CreateDocumentRequest createDocumentRequest = new CreateDocumentRequest("교육비 결재 요청", "EDUCATION", @@ -55,7 +55,7 @@ void save() { given(userService.findAllById(anyList())).willReturn(Arrays.asList(user, user)); //when - documentService.save(createDocumentRequest); + documentService.create(createDocumentRequest); //then verify(userService, times(1)).findAllById(anyList()); @@ -64,21 +64,21 @@ void save() { @Test @DisplayName("결재자가 한 명이라도 존재하지 않을 경우, 예외가 발생한다.") - void save_fail_not_exist_approver() { + void create_fail_not_exist_approver() { //given CreateDocumentRequest createDocumentRequest = new CreateDocumentRequest("교육비 결재 요청", "EDUCATION", "교육비", 1L, Collections.singletonList(1L)); String errorMessage = "식별번호와 일치하는 결재자를 모두 찾지 못했습니다."; //when, then - assertThatThrownBy(() -> documentService.save(createDocumentRequest)) + assertThatThrownBy(() -> documentService.create(createDocumentRequest)) .isInstanceOf(EntityNotFoundException.class) .hasMessageContaining(errorMessage); } @Test @DisplayName("문서를 조회한다.") - void select() { + void find() { //given User drafter = mock(User.class); given(drafter.getId()).willReturn(1L); @@ -92,10 +92,10 @@ void select() { given(document.getContents()).willReturn("교육비"); given(document.getApprovalState()).willReturn(ApprovalState.DRAFTING); - given(documentRepository.findByIdWithDrafter(anyLong())).willReturn(Optional.of(document)); + given(documentRepository.findDocumentAndDrafterById(anyLong())).willReturn(Optional.of(document)); //when - SelectDocumentResponse selectDocumentResponse = documentService.select(1L); + SelectDocumentResponse selectDocumentResponse = documentService.find(1L); //then assertThat(selectDocumentResponse).isNotNull(); @@ -103,16 +103,16 @@ void select() { @Test @DisplayName("문서가 존재하지 않을 시, 예외가 발생한다.") - void select_fail_not_found_document() { + void find_fail_not_found_document() { //when, then - assertThatThrownBy(() -> documentService.select(1L)) + assertThatThrownBy(() -> documentService.find(1L)) .isInstanceOf(EntityNotFoundException.class) .hasMessageContaining("해당하는 문서가 존재하지 않습니다."); } @Test @DisplayName("Outbox 문서 리스트를 조회한다.") - void selectOutBox() { + void findOutBox() { //given Document document = mock(Document.class); given(document.getId()).willReturn(1L); @@ -120,11 +120,11 @@ void selectOutBox() { given(document.getCategory()).willReturn(Category.EDUCATION); given(document.getApprovalState()).willReturn(ApprovalState.DRAFTING); - given(documentRepository.findAllWithDrafter(anyLong(), any(ApprovalState.class))) + given(documentRepository.findAllDocumentAndDrafterByDrafterIdAndApprovalState(anyLong(), any(ApprovalState.class))) .willReturn(Collections.singletonList(document)); //when - List selectMultiOutboxResponse = documentService.selectOutBox(1L); + List selectMultiOutboxResponse = documentService.findOutBox(1L); //then assertThat(selectMultiOutboxResponse).hasSize(1); @@ -132,15 +132,15 @@ void selectOutBox() { @Test @DisplayName("Outbox 문서가 없다면, 예외가 발생한다.") - void selectOutBox_fail_empty_result() { + void findOutBox_fail_empty_result() { //given String errorMessage = "현재 결재중인 문서가 존재하지 않습니다."; - given(documentRepository.findAllWithDrafter(anyLong(), any(ApprovalState.class))) + given(documentRepository.findAllDocumentAndDrafterByDrafterIdAndApprovalState(anyLong(), any(ApprovalState.class))) .willReturn(Collections.emptyList()); //when, then assertThatIllegalArgumentException() - .isThrownBy(() -> documentService.selectOutBox(1L)) + .isThrownBy(() -> documentService.findOutBox(1L)) .withMessageContaining(errorMessage); } } diff --git a/src/test/java/playground/service/team/TeamServiceTest.java b/src/test/java/playground/service/team/TeamServiceTest.java index 2d49955..eb5d039 100644 --- a/src/test/java/playground/service/team/TeamServiceTest.java +++ b/src/test/java/playground/service/team/TeamServiceTest.java @@ -66,12 +66,12 @@ void findByName_fail_not_found() { @Test @DisplayName("팀을 저장한다.") - void save() { + void create() { //given CreateTeamRequest createTeamRequest = new CreateTeamRequest("정산시스템팀"); //when - teamService.save(createTeamRequest); + teamService.create(createTeamRequest); //then verify(teamRepository, times(1)).save(any(Team.class)); @@ -79,27 +79,27 @@ void save() { @Test @DisplayName("중복된 팀 명으로 저장할경우, 예외가 발생한다.") - void save_fail_duplicated_name() { + void create_fail_duplicated_name() { //given CreateTeamRequest createTeamRequest = new CreateTeamRequest("정산시스템팀"); given(teamRepository.save(any(Team.class))).willThrow(new DuplicateKeyException("이름 중복")); //when, then assertThatIllegalArgumentException() - .isThrownBy(() -> teamService.save(createTeamRequest)) + .isThrownBy(() -> teamService.create(createTeamRequest)) .withMessageContaining("이미 존재하는 팀입니다."); } @Test @DisplayName("모든 팀을 조회한다.") - void selectAll() { + void findAll() { //given Team team1 = new Team("정산시스템팀"); Team team2 = new Team("서비스개발팀"); given(teamRepository.findAll()).willReturn(Arrays.asList(team1, team2)); //when - SelectTeamsResponse selectTeamsResponse = teamService.selectAll(); + SelectTeamsResponse selectTeamsResponse = teamService.findAll(); //then assertThat(selectTeamsResponse).isNotNull(); @@ -107,12 +107,12 @@ void selectAll() { @Test @DisplayName("존재하는 팀이 없을 경우, 예외가 발생한다.") - void selectAll_return_empty() { + void findAll_return_empty() { //given given(teamRepository.findAll()).willReturn(Collections.emptyList()); //when, then - assertThatThrownBy(() -> teamService.selectAll()) + assertThatThrownBy(() -> teamService.findAll()) .isInstanceOf(EntityNotFoundException.class) .hasMessageContaining("존재하는 팀이 없습니다."); } diff --git a/src/test/java/playground/service/user/UserServiceTest.java b/src/test/java/playground/service/user/UserServiceTest.java index bc3d60d..c5688dd 100644 --- a/src/test/java/playground/service/user/UserServiceTest.java +++ b/src/test/java/playground/service/user/UserServiceTest.java @@ -52,7 +52,7 @@ void save() { CreateUserRequest createUserRequest = new CreateUserRequest("a@naver.com", "Password123!", "김성빈", "정산시스템팀", TEAM_MEMBER.name()); //when - userService.save(createUserRequest); + userService.create(createUserRequest); //then verify(userRepository, times(1)).save(any(User.class)); @@ -69,7 +69,7 @@ void save_fail_duplicated_email() { //when, then assertThatIllegalArgumentException() - .isThrownBy(() -> userService.save(createUserRequest)) + .isThrownBy(() -> userService.create(createUserRequest)) .withMessageContaining("이미 가입된 이메일입니다."); } @@ -84,7 +84,7 @@ void save_fail_team_not_found() { //when, then assertThatIllegalArgumentException() - .isThrownBy(() -> userService.save(createUserRequest)) + .isThrownBy(() -> userService.create(createUserRequest)) .withMessageContaining("이미 가입된 이메일입니다."); } From 02bfcc547ab1d64435396705b4a479d16e379f1d Mon Sep 17 00:00:00 2001 From: Beenie93 Date: Sat, 4 Dec 2021 01:29:23 +0900 Subject: [PATCH 10/14] =?UTF-8?q?refactor=20:=20TeamService.findByName()?= =?UTF-8?q?=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Beenie93 --- .../repository/team/TeamRepository.java | 4 --- .../playground/service/team/TeamService.java | 6 ---- .../playground/service/user/UserService.java | 2 +- .../user/request/CreateUserRequest.java | 9 +++--- .../controller/user/UserControllerTest.java | 17 +++++------ .../service/team/TeamServiceTest.java | 28 ------------------- .../service/user/UserServiceTest.java | 19 ++++++------- 7 files changed, 24 insertions(+), 61 deletions(-) diff --git a/src/main/java/playground/repository/team/TeamRepository.java b/src/main/java/playground/repository/team/TeamRepository.java index e6cbfd5..439ff5c 100644 --- a/src/main/java/playground/repository/team/TeamRepository.java +++ b/src/main/java/playground/repository/team/TeamRepository.java @@ -3,9 +3,5 @@ import org.springframework.data.jpa.repository.JpaRepository; import playground.domain.team.Team; -import java.util.Optional; - public interface TeamRepository extends JpaRepository { - - Optional findByName(final String teamName); } diff --git a/src/main/java/playground/service/team/TeamService.java b/src/main/java/playground/service/team/TeamService.java index 26b48f6..079ebbe 100644 --- a/src/main/java/playground/service/team/TeamService.java +++ b/src/main/java/playground/service/team/TeamService.java @@ -20,12 +20,6 @@ public TeamService(final TeamRepository teamRepository) { this.teamRepository = teamRepository; } - @Transactional(readOnly = true) - public Team findByName(final String teamName) { - return teamRepository.findByName(teamName) - .orElseThrow(() -> new EntityNotFoundException(String.format("[%s] 팀 이름에 해당하는 팀이 존재하지 않습니다.", teamName))); - } - @Transactional public void create(final CreateTeamRequest createTeamRequest) { Team team = createTeamRequest.toTeam(); diff --git a/src/main/java/playground/service/user/UserService.java b/src/main/java/playground/service/user/UserService.java index bb0ab8f..743e731 100644 --- a/src/main/java/playground/service/user/UserService.java +++ b/src/main/java/playground/service/user/UserService.java @@ -26,7 +26,7 @@ public UserService(final UserRepository userRepository, final TeamService teamSe @Transactional public void create(final CreateUserRequest createUserRequest) { - Team team = teamService.findByName(createUserRequest.getTeamName()); + Team team = teamService.findById(createUserRequest.getTeamId()); User user = createUserRequest.toUser(team); save(user); } diff --git a/src/main/java/playground/service/user/request/CreateUserRequest.java b/src/main/java/playground/service/user/request/CreateUserRequest.java index 8c01c8b..044984c 100644 --- a/src/main/java/playground/service/user/request/CreateUserRequest.java +++ b/src/main/java/playground/service/user/request/CreateUserRequest.java @@ -9,6 +9,7 @@ import javax.validation.constraints.Email; import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; @Getter @NoArgsConstructor(access = AccessLevel.PRIVATE) @@ -24,18 +25,18 @@ public class CreateUserRequest { @NotBlank private String name; - @NotBlank - private String teamName; + @NotNull + private Long teamId; @NotBlank private String jobPosition; public CreateUserRequest(final String email, final String password, final String name, - final String teamName, final String jobPosition) { + final Long teamId, final String jobPosition) { this.email = email; this.password = password; this.name = name; - this.teamName = teamName; + this.teamId = teamId; this.jobPosition = jobPosition; } diff --git a/src/test/java/playground/controller/user/UserControllerTest.java b/src/test/java/playground/controller/user/UserControllerTest.java index ac32065..ad5ef42 100644 --- a/src/test/java/playground/controller/user/UserControllerTest.java +++ b/src/test/java/playground/controller/user/UserControllerTest.java @@ -4,6 +4,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.NullAndEmptySource; +import org.junit.jupiter.params.provider.NullSource; import org.junit.jupiter.params.provider.ValueSource; import org.mockito.Mock; import org.springframework.http.MediaType; @@ -37,7 +38,7 @@ protected Object setController() { @Test @DisplayName("사용자 생성 요청을 받아 사용자를 생성 후, HTTP 201을 반환한다.") void create() throws Exception { - CreateUserRequest createUserRequest = new CreateUserRequest("seongbeen93@naver.com", "password", "김성빈", "정산시스템팀", TEAM_MEMBER.getText()); + CreateUserRequest createUserRequest = new CreateUserRequest("seongbeen93@naver.com", "password", "김성빈", 1L, TEAM_MEMBER.getText()); mockMvc.perform(post("/api/users") .accept(MediaType.APPLICATION_JSON) @@ -50,7 +51,7 @@ void create() throws Exception { @ValueSource(strings = {"idnaver.com", "", "@naver.com"}) @DisplayName("이메일 형식이 올바르지 않을 경우, 예외가 발생한다.") void create_fail_invalid_email(String invalidEmail) throws Exception { - CreateUserRequest createUserRequest = new CreateUserRequest(invalidEmail, "password", "김성빈", "정산시스템팀", TEAM_MEMBER.getText()); + CreateUserRequest createUserRequest = new CreateUserRequest(invalidEmail, "password", "김성빈", 1L, TEAM_MEMBER.getText()); mockMvc.perform(post("/api/users") .accept(MediaType.APPLICATION_JSON) @@ -63,7 +64,7 @@ void create_fail_invalid_email(String invalidEmail) throws Exception { @NullAndEmptySource @DisplayName("비밀번호가 공백 또는 null있을 경우, 예외가 발생한다.") void create_fail_empty_password(String invalidPassword) throws Exception { - CreateUserRequest createUserRequest = new CreateUserRequest("seongbeen93@naver.com", invalidPassword, "김성빈", "정산시스템팀", TEAM_MEMBER.getText()); + CreateUserRequest createUserRequest = new CreateUserRequest("seongbeen93@naver.com", invalidPassword, "김성빈", 1L, TEAM_MEMBER.getText()); mockMvc.perform(post("/api/users") .accept(MediaType.APPLICATION_JSON) @@ -76,7 +77,7 @@ void create_fail_empty_password(String invalidPassword) throws Exception { @NullAndEmptySource @DisplayName("이름이 공백 또는 null일 경우, 예외가 발생한다.") void create_fail_empty_name(String invalidName) throws Exception { - CreateUserRequest createUserRequest = new CreateUserRequest("seongbeen93@naver.com", "password", invalidName, "정산시스템팀", TEAM_MEMBER.getText()); + CreateUserRequest createUserRequest = new CreateUserRequest("seongbeen93@naver.com", "password", invalidName, 1L, TEAM_MEMBER.getText()); mockMvc.perform(post("/api/users") .accept(MediaType.APPLICATION_JSON) @@ -86,10 +87,10 @@ void create_fail_empty_name(String invalidName) throws Exception { } @ParameterizedTest - @NullAndEmptySource - @DisplayName("팀명이 공백 또는 null일 경우, 예외가 발생한다.") - void create_fail_empty_team(String invalidTeamName) throws Exception { - CreateUserRequest createUserRequest = new CreateUserRequest("seongbeen93@naver.com", "password", "김성빈", invalidTeamName, TEAM_MEMBER.getText()); + @NullSource + @DisplayName("팀 식별번호가 null일 경우, 예외가 발생한다.") + void create_fail_empty_team(Long invalidTeamId) throws Exception { + CreateUserRequest createUserRequest = new CreateUserRequest("seongbeen93@naver.com", "password", "김성빈", invalidTeamId, TEAM_MEMBER.getText()); mockMvc.perform(post("/api/users") .accept(MediaType.APPLICATION_JSON) diff --git a/src/test/java/playground/service/team/TeamServiceTest.java b/src/test/java/playground/service/team/TeamServiceTest.java index eb5d039..1b29705 100644 --- a/src/test/java/playground/service/team/TeamServiceTest.java +++ b/src/test/java/playground/service/team/TeamServiceTest.java @@ -22,7 +22,6 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -37,33 +36,6 @@ class TeamServiceTest { @InjectMocks private TeamService teamService; - @Test - @DisplayName("팀 이름을 팀을 조회한다.") - void findByName() { - //given - String name = "정산서비스팀"; - Team team = new Team(name); - given(teamRepository.findByName(anyString())).willReturn(Optional.of(team)); - - //when - Team fetchedTeam = teamService.findByName(name); - - //then - assertThat(fetchedTeam).isEqualTo(team); - } - - @Test - @DisplayName("팀 이름과 일치하는 팀이 존재하지 않을 경우, 예외가 발생한다.") - void findByName_fail_not_found() { - //given - given(teamRepository.findByName(anyString())).willReturn(Optional.empty()); - - //when, then - assertThatThrownBy(() -> teamService.findByName("존재하지 않는 팀 이름")) - .isInstanceOf(EntityNotFoundException.class) - .hasMessageContaining("팀이 존재하지 않습니다."); - } - @Test @DisplayName("팀을 저장한다.") void create() { diff --git a/src/test/java/playground/service/user/UserServiceTest.java b/src/test/java/playground/service/user/UserServiceTest.java index c5688dd..2790059 100644 --- a/src/test/java/playground/service/user/UserServiceTest.java +++ b/src/test/java/playground/service/user/UserServiceTest.java @@ -24,7 +24,6 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -45,11 +44,11 @@ class UserServiceTest { @Test @DisplayName("사용자를 저장한다.") - void save() { + void create() { //given Team team = mock(Team.class); - given(teamService.findByName(anyString())).willReturn(team); - CreateUserRequest createUserRequest = new CreateUserRequest("a@naver.com", "Password123!", "김성빈", "정산시스템팀", TEAM_MEMBER.name()); + given(teamService.findById(anyLong())).willReturn(team); + CreateUserRequest createUserRequest = new CreateUserRequest("a@naver.com", "Password123!", "김성빈", 1L, TEAM_MEMBER.name()); //when userService.create(createUserRequest); @@ -60,12 +59,12 @@ void save() { @Test @DisplayName("중복된 이메일일 경우, 예외가 발생한다.") - void save_fail_duplicated_email() { + void create_fail_duplicated_email() { //given Team team = mock(Team.class); - given(teamService.findByName(anyString())).willReturn(team); + given(teamService.findById(anyLong())).willReturn(team); given(userRepository.save(any(User.class))).willThrow(new DuplicateKeyException("이메일 중복")); - CreateUserRequest createUserRequest = new CreateUserRequest("a@naver.com", "Password123!", "김성빈", "정산시스템팀", TEAM_MEMBER.name()); + CreateUserRequest createUserRequest = new CreateUserRequest("a@naver.com", "Password123!", "김성빈", 1L, TEAM_MEMBER.name()); //when, then assertThatIllegalArgumentException() @@ -75,12 +74,12 @@ void save_fail_duplicated_email() { @Test @DisplayName("팀이 존재하지 않을 경우, 에외가 발생한다.") - void save_fail_team_not_found() { + void create_fail_team_not_found() { //given Team team = mock(Team.class); - given(teamService.findByName(anyString())).willReturn(team); + given(teamService.findById(anyLong())).willReturn(team); given(userRepository.save(any(User.class))).willThrow(new DuplicateKeyException("이메일 중복")); - CreateUserRequest createUserRequest = new CreateUserRequest("a@naver.com", "Password123!", "김성빈", "정산시스템팀", TEAM_MEMBER.name()); + CreateUserRequest createUserRequest = new CreateUserRequest("a@naver.com", "Password123!", "김성빈", 1L, TEAM_MEMBER.name()); //when, then assertThatIllegalArgumentException() From 82569a0080e5181830671df89cea762fe7ce8e8d Mon Sep 17 00:00:00 2001 From: Beenie93 Date: Sat, 4 Dec 2021 01:34:57 +0900 Subject: [PATCH 11/14] =?UTF-8?q?refactor=20:=20=EB=B6=88=ED=95=84?= =?UTF-8?q?=EC=9A=94=ED=95=9C=20Response=20Wrapper=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Beenie93 --- .../controller/team/TeamController.java | 9 ++++---- .../controller/user/UserController.java | 9 ++++---- .../playground/service/team/TeamService.java | 10 +++++--- .../team/response/SelectTeamsResponse.java | 23 ------------------- .../playground/service/user/UserService.java | 10 +++++--- .../response/SelectAllUserInTeamResponse.java | 22 ------------------ .../controller/user/UserControllerTest.java | 6 ++--- .../service/team/TeamServiceTest.java | 10 ++++---- 8 files changed, 33 insertions(+), 66 deletions(-) delete mode 100644 src/main/java/playground/service/team/response/SelectTeamsResponse.java delete mode 100644 src/main/java/playground/service/user/response/SelectAllUserInTeamResponse.java diff --git a/src/main/java/playground/controller/team/TeamController.java b/src/main/java/playground/controller/team/TeamController.java index 3719a2e..f1024c4 100644 --- a/src/main/java/playground/controller/team/TeamController.java +++ b/src/main/java/playground/controller/team/TeamController.java @@ -9,9 +9,10 @@ import org.springframework.web.bind.annotation.RestController; import playground.service.team.TeamService; import playground.service.team.request.CreateTeamRequest; -import playground.service.team.response.SelectTeamsResponse; +import playground.service.team.response.SelectTeamResponse; import javax.validation.Valid; +import java.util.List; @RestController @RequestMapping(path = "/api/teams") @@ -30,8 +31,8 @@ public ResponseEntity create(@RequestBody @Valid final CreateTeamRequest c } @GetMapping - public ResponseEntity findAll() { - SelectTeamsResponse selectTeamsResponse = teamService.findAll(); - return ResponseEntity.ok(selectTeamsResponse); + public ResponseEntity> findAll() { + List selectTeamResponses = teamService.findAll(); + return ResponseEntity.ok(selectTeamResponses); } } diff --git a/src/main/java/playground/controller/user/UserController.java b/src/main/java/playground/controller/user/UserController.java index 46ab16e..2e93f99 100644 --- a/src/main/java/playground/controller/user/UserController.java +++ b/src/main/java/playground/controller/user/UserController.java @@ -10,9 +10,10 @@ import org.springframework.web.bind.annotation.RestController; import playground.service.user.UserService; import playground.service.user.request.CreateUserRequest; -import playground.service.user.response.SelectAllUserInTeamResponse; +import playground.service.user.response.SelectUserResponse; import javax.validation.Valid; +import java.util.List; @RestController @RequestMapping(path = "/api/users") @@ -31,8 +32,8 @@ public ResponseEntity create(@RequestBody @Valid final CreateUserRequest c } @GetMapping() - public ResponseEntity findAllUserInTeam(@RequestParam final Long teamId) { - SelectAllUserInTeamResponse selectAllUserInTeamResponse = userService.findAllUserInTeam(teamId); - return ResponseEntity.ok(selectAllUserInTeamResponse); + public ResponseEntity> findAllUserInTeam(@RequestParam final Long teamId) { + List selectUserResponses = userService.findAllUserInTeam(teamId); + return ResponseEntity.ok(selectUserResponses); } } diff --git a/src/main/java/playground/service/team/TeamService.java b/src/main/java/playground/service/team/TeamService.java index 079ebbe..2511681 100644 --- a/src/main/java/playground/service/team/TeamService.java +++ b/src/main/java/playground/service/team/TeamService.java @@ -6,10 +6,11 @@ import playground.domain.team.Team; import playground.repository.team.TeamRepository; import playground.service.team.request.CreateTeamRequest; -import playground.service.team.response.SelectTeamsResponse; +import playground.service.team.response.SelectTeamResponse; import javax.persistence.EntityNotFoundException; import java.util.List; +import java.util.stream.Collectors; @Service public class TeamService { @@ -35,10 +36,13 @@ private void save(final Team team) { } @Transactional(readOnly = true) - public SelectTeamsResponse findAll() { + public List findAll() { List teams = teamRepository.findAll(); checkEmpty(teams); - return new SelectTeamsResponse(teams); + + return teams.stream() + .map(SelectTeamResponse::new) + .collect(Collectors.toList()); } private void checkEmpty(final List teams) { diff --git a/src/main/java/playground/service/team/response/SelectTeamsResponse.java b/src/main/java/playground/service/team/response/SelectTeamsResponse.java deleted file mode 100644 index 67d5707..0000000 --- a/src/main/java/playground/service/team/response/SelectTeamsResponse.java +++ /dev/null @@ -1,23 +0,0 @@ -package playground.service.team.response; - - -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; -import playground.domain.team.Team; - -import java.util.List; -import java.util.stream.Collectors; - -@Getter -@NoArgsConstructor(access = AccessLevel.PRIVATE) -public class SelectTeamsResponse { - - private List selectTeamResponses; - - public SelectTeamsResponse(final List teams) { - this.selectTeamResponses = teams.stream() - .map(SelectTeamResponse::new) - .collect(Collectors.toList()); - } -} diff --git a/src/main/java/playground/service/user/UserService.java b/src/main/java/playground/service/user/UserService.java index 743e731..20b7771 100644 --- a/src/main/java/playground/service/user/UserService.java +++ b/src/main/java/playground/service/user/UserService.java @@ -8,10 +8,11 @@ import playground.repository.user.UserRepository; import playground.service.team.TeamService; import playground.service.user.request.CreateUserRequest; -import playground.service.user.response.SelectAllUserInTeamResponse; +import playground.service.user.response.SelectUserResponse; import javax.persistence.EntityNotFoundException; import java.util.List; +import java.util.stream.Collectors; @Service public class UserService { @@ -60,8 +61,11 @@ public User findById(final Long userId) { } @Transactional(readOnly = true) - public SelectAllUserInTeamResponse findAllUserInTeam(final Long teamId) { + public List findAllUserInTeam(final Long teamId) { Team team = teamService.findById(teamId); - return new SelectAllUserInTeamResponse(team.getUsers()); + + return team.getUsers().stream() + .map(SelectUserResponse::new) + .collect(Collectors.toList()); } } diff --git a/src/main/java/playground/service/user/response/SelectAllUserInTeamResponse.java b/src/main/java/playground/service/user/response/SelectAllUserInTeamResponse.java deleted file mode 100644 index 62df78a..0000000 --- a/src/main/java/playground/service/user/response/SelectAllUserInTeamResponse.java +++ /dev/null @@ -1,22 +0,0 @@ -package playground.service.user.response; - -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; -import playground.domain.user.User; - -import java.util.List; -import java.util.stream.Collectors; - -@Getter -@NoArgsConstructor(access = AccessLevel.PRIVATE) -public class SelectAllUserInTeamResponse { - - private List selectUserResponses; - - public SelectAllUserInTeamResponse(final List users) { - this.selectUserResponses = users.stream() - .map(SelectUserResponse::new) - .collect(Collectors.toList()); - } -} diff --git a/src/test/java/playground/controller/user/UserControllerTest.java b/src/test/java/playground/controller/user/UserControllerTest.java index ad5ef42..1e02dee 100644 --- a/src/test/java/playground/controller/user/UserControllerTest.java +++ b/src/test/java/playground/controller/user/UserControllerTest.java @@ -13,7 +13,7 @@ import playground.domain.user.User; import playground.service.user.UserService; import playground.service.user.request.CreateUserRequest; -import playground.service.user.response.SelectAllUserInTeamResponse; +import playground.service.user.response.SelectUserResponse; import java.util.Collections; @@ -109,8 +109,8 @@ void findAllUserInTeam() throws Exception { given(user.getJobPosition()).willReturn(TEAM_MEMBER); given(user.getTeam()).willReturn(team); given(team.getName()).willReturn("운영팀"); - SelectAllUserInTeamResponse selectAllUserInTeamResponse = new SelectAllUserInTeamResponse(Collections.singletonList(user)); - given(userService.findAllUserInTeam(anyLong())).willReturn(selectAllUserInTeamResponse); + SelectUserResponse selectUserResponse = new SelectUserResponse(user); + given(userService.findAllUserInTeam(anyLong())).willReturn(Collections.singletonList(selectUserResponse)); mockMvc.perform(get("/api/users") .param("teamId", "1") diff --git a/src/test/java/playground/service/team/TeamServiceTest.java b/src/test/java/playground/service/team/TeamServiceTest.java index 1b29705..60e94fb 100644 --- a/src/test/java/playground/service/team/TeamServiceTest.java +++ b/src/test/java/playground/service/team/TeamServiceTest.java @@ -10,11 +10,12 @@ import playground.domain.team.Team; import playground.repository.team.TeamRepository; import playground.service.team.request.CreateTeamRequest; -import playground.service.team.response.SelectTeamsResponse; +import playground.service.team.response.SelectTeamResponse; import javax.persistence.EntityNotFoundException; import java.util.Arrays; import java.util.Collections; +import java.util.List; import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; @@ -68,13 +69,14 @@ void findAll() { //given Team team1 = new Team("정산시스템팀"); Team team2 = new Team("서비스개발팀"); - given(teamRepository.findAll()).willReturn(Arrays.asList(team1, team2)); + List teams = Arrays.asList(team1, team2); + given(teamRepository.findAll()).willReturn(teams); //when - SelectTeamsResponse selectTeamsResponse = teamService.findAll(); + List selectTeamResponses = teamService.findAll(); //then - assertThat(selectTeamsResponse).isNotNull(); + assertThat(selectTeamResponses).hasSize(teams.size()); } @Test From e5593bf27cbe6cd7c2f986e7a671e3015366bc9f Mon Sep 17 00:00:00 2001 From: Beenie93 Date: Sat, 4 Dec 2021 02:03:46 +0900 Subject: [PATCH 12/14] =?UTF-8?q?feat=20:=20=EB=AA=A8=EB=93=A0=20=EB=AC=B8?= =?UTF-8?q?=EC=84=9C=20=ED=95=AD=EB=AA=A9=EC=9D=84=20=EC=A1=B0=ED=9A=8C?= =?UTF-8?q?=ED=95=98=EB=8A=94=20API=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Beenie93 --- .../document/DocumentController.java | 7 +++ .../document/DocumentRepository.java | 4 ++ .../service/document/DocumentService.java | 5 ++ .../response/SelectCategoryResponse.java | 23 +++++++++ .../document/DocumentControllerTest.java | 8 +++ .../document/DocumentRepositoryTest.java | 49 +++++++++++++++++++ 6 files changed, 96 insertions(+) create mode 100644 src/main/java/playground/service/document/response/SelectCategoryResponse.java diff --git a/src/main/java/playground/controller/document/DocumentController.java b/src/main/java/playground/controller/document/DocumentController.java index 746e737..68a4785 100644 --- a/src/main/java/playground/controller/document/DocumentController.java +++ b/src/main/java/playground/controller/document/DocumentController.java @@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.RestController; import playground.service.document.DocumentService; import playground.service.document.request.CreateDocumentRequest; +import playground.service.document.response.SelectCategoryResponse; import playground.service.document.response.SelectDocumentResponse; import playground.service.document.response.SelectSingleOutBoxResponse; @@ -44,4 +45,10 @@ public ResponseEntity> findOutBox(final @Reques List selectMultiOutBoxResponse = documentService.findOutBox(drafterId); return ResponseEntity.ok(selectMultiOutBoxResponse); } + + @GetMapping("/categories") + public ResponseEntity> findCategories() { + List selectCategoryResponses = documentService.findCategories(); + return ResponseEntity.ok(selectCategoryResponses); + } } diff --git a/src/main/java/playground/repository/document/DocumentRepository.java b/src/main/java/playground/repository/document/DocumentRepository.java index f1e36d5..fd0964f 100644 --- a/src/main/java/playground/repository/document/DocumentRepository.java +++ b/src/main/java/playground/repository/document/DocumentRepository.java @@ -5,6 +5,7 @@ import org.springframework.data.repository.query.Param; import playground.domain.document.Document; import playground.domain.document.vo.ApprovalState; +import playground.service.document.response.SelectCategoryResponse; import java.util.List; import java.util.Optional; @@ -16,4 +17,7 @@ public interface DocumentRepository extends JpaRepository { @Query("select d from Document d join fetch d.drafter where d.drafter.id = :drafter_id and d.approvalState = :approval_state") List findAllDocumentAndDrafterByDrafterIdAndApprovalState(@Param("drafter_id") final Long drafterId, @Param("approval_state") final ApprovalState approvalState); + + @Query("select distinct new playground.service.document.response.SelectCategoryResponse(d.category) from Document d") + List findCategories(); } diff --git a/src/main/java/playground/service/document/DocumentService.java b/src/main/java/playground/service/document/DocumentService.java index e44a4d9..5b0ed2d 100644 --- a/src/main/java/playground/service/document/DocumentService.java +++ b/src/main/java/playground/service/document/DocumentService.java @@ -7,6 +7,7 @@ import playground.domain.user.User; import playground.repository.document.DocumentRepository; import playground.service.document.request.CreateDocumentRequest; +import playground.service.document.response.SelectCategoryResponse; import playground.service.document.response.SelectDocumentResponse; import playground.service.document.response.SelectSingleOutBoxResponse; import playground.service.user.UserService; @@ -80,4 +81,8 @@ private void checkEmpty(final List documents) { throw new IllegalArgumentException("현재 결재중인 문서가 존재하지 않습니다."); } } + + public List findCategories() { + return documentRepository.findCategories(); + } } diff --git a/src/main/java/playground/service/document/response/SelectCategoryResponse.java b/src/main/java/playground/service/document/response/SelectCategoryResponse.java new file mode 100644 index 0000000..b805f5d --- /dev/null +++ b/src/main/java/playground/service/document/response/SelectCategoryResponse.java @@ -0,0 +1,23 @@ +package playground.service.document.response; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import playground.domain.document.vo.Category; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class SelectCategoryResponse { + + private Category category; + + public SelectCategoryResponse(final Category category) { + this.category = category; + } + + public String getValue() { + return category.name(); + } + + public String getText() { + return category.getText(); + } +} diff --git a/src/test/java/playground/controller/document/DocumentControllerTest.java b/src/test/java/playground/controller/document/DocumentControllerTest.java index 1f8c55f..5651371 100644 --- a/src/test/java/playground/controller/document/DocumentControllerTest.java +++ b/src/test/java/playground/controller/document/DocumentControllerTest.java @@ -125,4 +125,12 @@ void findOutBox() throws Exception { .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()); } + + @Test + @DisplayName("모든 문서 항목을 조회한다.") + void findCategories() throws Exception { + mockMvc.perform(get("/api/documents/categories") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + } } diff --git a/src/test/java/playground/repository/document/DocumentRepositoryTest.java b/src/test/java/playground/repository/document/DocumentRepositoryTest.java index 30d1f0e..50b3163 100644 --- a/src/test/java/playground/repository/document/DocumentRepositoryTest.java +++ b/src/test/java/playground/repository/document/DocumentRepositoryTest.java @@ -11,6 +11,7 @@ import playground.domain.team.Team; import playground.domain.user.User; import playground.domain.user.vo.JobPosition; +import playground.service.document.response.SelectCategoryResponse; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; @@ -102,4 +103,52 @@ void findAllDocumentAndDrafterByDrafterIdAndApprovalState() { assertThat(documents).hasSize(1); assertThat(persistenceUnitUtil.isLoaded(documents.get(0).getDrafter())).isTrue(); } + + @Test + @DisplayName("중복 제거된 문서 항목을 반환한다.") + void findCategories() { + //given + Team team = new Team("정산시스템팀"); + entityManager.persist(team); + + User drafter = User.builder() + .email("test@naver.com") + .password("Password123!") + .name("drafter") + .team(team) + .jobPosition(JobPosition.TEAM_MEMBER) + .build(); + entityManager.persist(drafter); + + Document document = Document.builder() + .drafter(drafter) + .category(Category.EDUCATION) + .title("교육비 정산") + .contents("교육비 정산 결재") + .build(); + Document document2 = Document.builder() + .drafter(drafter) + .category(Category.EDUCATION) + .title("교육비 정산") + .contents("교육비 정산 결재") + .build(); + Document document3 = Document.builder() + .drafter(drafter) + .category(Category.OPERATING_EXPENSES) + .title("교육비 정산") + .contents("교육비 정산 결재") + .build(); + documentRepository.save(document); + documentRepository.save(document2); + documentRepository.save(document3); + + //when + List selectCategoryResponses = documentRepository.findCategories(); + + //then + assertThat(selectCategoryResponses).hasSize(2); + assertThat(selectCategoryResponses) + .extracting("category") + .containsExactly(Category.EDUCATION, Category.OPERATING_EXPENSES); + } } From b73acaba1c6e35e33f838d821674ebcd11aae929 Mon Sep 17 00:00:00 2001 From: Beenie93 Date: Sat, 4 Dec 2021 03:05:07 +0900 Subject: [PATCH 13/14] =?UTF-8?q?refactor=20:=20=EB=AC=B8=EC=84=9C=20?= =?UTF-8?q?=EB=8B=A8=EA=B1=B4=20=EC=A1=B0=ED=9A=8C=20=EC=8B=9C=20=EA=B8=B0?= =?UTF-8?q?=EC=95=88=EC=9E=90,=20=EA=B2=B0=EC=9E=AC=20=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=20=EA=B4=80=EB=A0=A8=20=EC=A0=95=EB=B3=B4=EB=8F=84=20=ED=95=A8?= =?UTF-8?q?=EA=BB=98=20=EA=B0=80=EC=A0=B8=EC=98=A4=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Beenie93 --- .../playground/domain/document/Document.java | 5 ++++ .../document/DocumentApprovalRepository.java | 14 +++++++++ .../service/document/DocumentService.java | 14 ++++++++- .../response/SelectApproverResponse.java | 29 +++++++++++++++++++ .../response/SelectDocumentResponse.java | 17 +++++++---- .../service/document/DocumentServiceTest.java | 15 ++++++++++ 6 files changed, 88 insertions(+), 6 deletions(-) create mode 100644 src/main/java/playground/repository/document/DocumentApprovalRepository.java create mode 100644 src/main/java/playground/service/document/response/SelectApproverResponse.java diff --git a/src/main/java/playground/domain/document/Document.java b/src/main/java/playground/domain/document/Document.java index ae420d6..90578fd 100644 --- a/src/main/java/playground/domain/document/Document.java +++ b/src/main/java/playground/domain/document/Document.java @@ -21,6 +21,7 @@ import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; +import java.util.Collections; import java.util.List; @Entity @@ -69,4 +70,8 @@ private Document(final String title, final Category category, public void enrollApprovals(final List approvers, final Document document) { documentApprovals.enroll(approvers, document); } + + public List getDocumentApprovals() { + return Collections.unmodifiableList(documentApprovals.getDocumentApprovals()); + } } diff --git a/src/main/java/playground/repository/document/DocumentApprovalRepository.java b/src/main/java/playground/repository/document/DocumentApprovalRepository.java new file mode 100644 index 0000000..acbf3f7 --- /dev/null +++ b/src/main/java/playground/repository/document/DocumentApprovalRepository.java @@ -0,0 +1,14 @@ +package playground.repository.document; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import playground.domain.document.DocumentApproval; + +import java.util.List; + +public interface DocumentApprovalRepository extends JpaRepository { + + @Query("select d from DocumentApproval d join fetch d.approver a join fetch a.team where d.id in :documentApprovalIds") + List findAllDocumentApprovalAndApproverAndTeamByIds(@Param("documentApprovalIds") List documentApprovalIds); +} diff --git a/src/main/java/playground/service/document/DocumentService.java b/src/main/java/playground/service/document/DocumentService.java index 5b0ed2d..d3c74a0 100644 --- a/src/main/java/playground/service/document/DocumentService.java +++ b/src/main/java/playground/service/document/DocumentService.java @@ -3,8 +3,10 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import playground.domain.document.Document; +import playground.domain.document.DocumentApproval; import playground.domain.document.vo.ApprovalState; import playground.domain.user.User; +import playground.repository.document.DocumentApprovalRepository; import playground.repository.document.DocumentRepository; import playground.service.document.request.CreateDocumentRequest; import playground.service.document.response.SelectCategoryResponse; @@ -20,11 +22,14 @@ public class DocumentService { private final DocumentRepository documentRepository; + private final DocumentApprovalRepository documentApprovalRepository; private final UserService userService; public DocumentService(final DocumentRepository documentRepository, + final DocumentApprovalRepository documentApprovalRepository, final UserService userService) { this.documentRepository = documentRepository; + this.documentApprovalRepository = documentApprovalRepository; this.userService = userService; } @@ -58,7 +63,14 @@ private List findAllUserById(final List approverIds) { @Transactional(readOnly = true) public SelectDocumentResponse find(final Long documentId) { Document document = findDocumentAndDrafterById(documentId); - return new SelectDocumentResponse(document); + + List documentApprovalIds = document.getDocumentApprovals() + .stream() + .map(DocumentApproval::getId) + .collect(Collectors.toList()); + List documentApprovals = documentApprovalRepository.findAllDocumentApprovalAndApproverAndTeamByIds(documentApprovalIds); + + return new SelectDocumentResponse(document, documentApprovals); } private Document findDocumentAndDrafterById(final Long documentId) { diff --git a/src/main/java/playground/service/document/response/SelectApproverResponse.java b/src/main/java/playground/service/document/response/SelectApproverResponse.java new file mode 100644 index 0000000..9fc8811 --- /dev/null +++ b/src/main/java/playground/service/document/response/SelectApproverResponse.java @@ -0,0 +1,29 @@ +package playground.service.document.response; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import playground.domain.document.DocumentApproval; +import playground.domain.document.vo.ApprovalState; + +@Getter +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class SelectApproverResponse { + + private String approverTeamName; + private String approverName; + private ApprovalState approvalState; + private Integer approvalOrder; + private String approvalComment; + private String approvalStateText; + + public SelectApproverResponse(final DocumentApproval documentApproval) { + this.approverTeamName = documentApproval.getApprover().getTeam().getName(); + this.approverName = documentApproval.getApprover().getName(); + ; + this.approvalState = documentApproval.getApprovalState(); + this.approvalOrder = documentApproval.getApprovalOrder(); + this.approvalComment = documentApproval.getApprovalComment(); + this.approvalStateText = documentApproval.getApprovalState().getText(); + } +} diff --git a/src/main/java/playground/service/document/response/SelectDocumentResponse.java b/src/main/java/playground/service/document/response/SelectDocumentResponse.java index dfaf3be..c5f87bf 100644 --- a/src/main/java/playground/service/document/response/SelectDocumentResponse.java +++ b/src/main/java/playground/service/document/response/SelectDocumentResponse.java @@ -4,8 +4,13 @@ import lombok.Getter; import lombok.NoArgsConstructor; import playground.domain.document.Document; +import playground.domain.document.DocumentApproval; import playground.domain.document.vo.ApprovalState; import playground.domain.document.vo.Category; +import playground.service.user.response.SelectUserResponse; + +import java.util.List; +import java.util.stream.Collectors; @Getter @NoArgsConstructor(access = AccessLevel.PRIVATE) @@ -15,20 +20,22 @@ public class SelectDocumentResponse { private String title; private Category category; private String contents; - private Long userId; private ApprovalState approvalState; - private String userName; + private SelectUserResponse drafter; + private List approvers; private String categoryText; private String approvalStateText; - public SelectDocumentResponse(final Document document) { + public SelectDocumentResponse(final Document document, final List documentApprovals) { this.id = document.getId(); this.title = document.getTitle(); this.category = document.getCategory(); this.contents = document.getContents(); - this.userId = document.getDrafter().getId(); this.approvalState = document.getApprovalState(); - this.userName = document.getDrafter().getName(); + this.drafter = new SelectUserResponse(document.getDrafter()); + this.approvers = documentApprovals.stream() + .map(SelectApproverResponse::new) + .collect(Collectors.toList()); this.categoryText = document.getCategory().getText(); this.approvalStateText = document.getApprovalState().getText(); } diff --git a/src/test/java/playground/service/document/DocumentServiceTest.java b/src/test/java/playground/service/document/DocumentServiceTest.java index dd6076c..06e8c31 100644 --- a/src/test/java/playground/service/document/DocumentServiceTest.java +++ b/src/test/java/playground/service/document/DocumentServiceTest.java @@ -7,9 +7,13 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import playground.domain.document.Document; +import playground.domain.document.DocumentApproval; import playground.domain.document.vo.ApprovalState; import playground.domain.document.vo.Category; +import playground.domain.team.Team; import playground.domain.user.User; +import playground.domain.user.vo.JobPosition; +import playground.repository.document.DocumentApprovalRepository; import playground.repository.document.DocumentRepository; import playground.service.document.request.CreateDocumentRequest; import playground.service.document.response.SelectDocumentResponse; @@ -39,6 +43,9 @@ class DocumentServiceTest { @Mock private DocumentRepository documentRepository; + @Mock + private DocumentApprovalRepository documentApprovalRepository; + @Mock private UserService userService; @@ -83,6 +90,10 @@ void find() { User drafter = mock(User.class); given(drafter.getId()).willReturn(1L); given(drafter.getName()).willReturn("기안자"); + given(drafter.getJobPosition()).willReturn(JobPosition.PART_MANAGER); + + Team team = mock(Team.class); + given(drafter.getTeam()).willReturn(team); Document document = mock(Document.class); given(document.getId()).willReturn(1L); @@ -92,6 +103,10 @@ void find() { given(document.getContents()).willReturn("교육비"); given(document.getApprovalState()).willReturn(ApprovalState.DRAFTING); + DocumentApproval documentApproval = mock(DocumentApproval.class); + given(documentApproval.getApprover()).willReturn(drafter); + given(documentApproval.getApprovalState()).willReturn(ApprovalState.DRAFTING); + given(documentApprovalRepository.findAllDocumentApprovalAndApproverAndTeamByIds(anyList())).willReturn(Collections.singletonList(documentApproval)); given(documentRepository.findDocumentAndDrafterById(anyLong())).willReturn(Optional.of(document)); //when From 1ffdef593451bf77676ae1248980c0c0ccdbac17 Mon Sep 17 00:00:00 2001 From: Beenie93 Date: Mon, 6 Dec 2021 22:59:17 +0900 Subject: [PATCH 14/14] =?UTF-8?q?refactor=20:=20Collection=20fetch=20join?= =?UTF-8?q?=20=ED=95=B4=EC=98=AC=20=EC=88=98=20=EC=9E=88=EB=8F=84=EB=A1=9D?= =?UTF-8?q?=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20enrollApprovals()=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Beenie93 --- .../playground/domain/document/Document.java | 4 +-- .../domain/document/DocumentApprovals.java | 3 -- .../document/DocumentRepository.java | 8 ++--- .../service/document/DocumentService.java | 9 ++--- src/test/java/playground/QueryTest.java | 34 +++++++++++++++++++ .../document/DocumentRepositoryTest.java | 9 +++-- .../service/document/DocumentServiceTest.java | 2 +- 7 files changed, 52 insertions(+), 17 deletions(-) create mode 100644 src/test/java/playground/QueryTest.java diff --git a/src/main/java/playground/domain/document/Document.java b/src/main/java/playground/domain/document/Document.java index 90578fd..4324084 100644 --- a/src/main/java/playground/domain/document/Document.java +++ b/src/main/java/playground/domain/document/Document.java @@ -67,8 +67,8 @@ private Document(final String title, final Category category, this.approvalState = ApprovalState.DRAFTING; } - public void enrollApprovals(final List approvers, final Document document) { - documentApprovals.enroll(approvers, document); + public void enrollApprovals(final List approvers) { + documentApprovals.enroll(approvers, this); } public List getDocumentApprovals() { diff --git a/src/main/java/playground/domain/document/DocumentApprovals.java b/src/main/java/playground/domain/document/DocumentApprovals.java index 06325f9..9e782fe 100644 --- a/src/main/java/playground/domain/document/DocumentApprovals.java +++ b/src/main/java/playground/domain/document/DocumentApprovals.java @@ -1,8 +1,6 @@ package playground.domain.document; -import lombok.AccessLevel; import lombok.Getter; -import lombok.NoArgsConstructor; import playground.domain.user.User; import javax.persistence.CascadeType; @@ -14,7 +12,6 @@ @Getter @Embeddable -@NoArgsConstructor(access = AccessLevel.PUBLIC) public class DocumentApprovals { @OneToMany(mappedBy = "document", cascade = CascadeType.ALL, orphanRemoval = true) diff --git a/src/main/java/playground/repository/document/DocumentRepository.java b/src/main/java/playground/repository/document/DocumentRepository.java index fd0964f..720ae4c 100644 --- a/src/main/java/playground/repository/document/DocumentRepository.java +++ b/src/main/java/playground/repository/document/DocumentRepository.java @@ -12,11 +12,11 @@ public interface DocumentRepository extends JpaRepository { - @Query("select d from Document d join fetch d.drafter where d.id = :document_id") - Optional findDocumentAndDrafterById(@Param("document_id") final Long documentId); + @Query("select d from Document d join fetch d.drafter join fetch d.documentApprovals.documentApprovals where d.id = :documentId") + Optional findDocumentAndDrafterAndDocumentApprovalsById(@Param("documentId") final Long documentId); - @Query("select d from Document d join fetch d.drafter where d.drafter.id = :drafter_id and d.approvalState = :approval_state") - List findAllDocumentAndDrafterByDrafterIdAndApprovalState(@Param("drafter_id") final Long drafterId, @Param("approval_state") final ApprovalState approvalState); + @Query("select d from Document d join fetch d.drafter where d.drafter.id = :documentId and d.approvalState = :approvalState") + List findAllDocumentAndDrafterByDrafterIdAndApprovalState(@Param("documentId") final Long drafterId, @Param("approvalState") final ApprovalState approvalState); @Query("select distinct new playground.service.document.response.SelectCategoryResponse(d.category) from Document d") List findCategories(); diff --git a/src/main/java/playground/service/document/DocumentService.java b/src/main/java/playground/service/document/DocumentService.java index d3c74a0..7a400bd 100644 --- a/src/main/java/playground/service/document/DocumentService.java +++ b/src/main/java/playground/service/document/DocumentService.java @@ -42,7 +42,7 @@ public void create(final CreateDocumentRequest createDocumentRequest) { User drafter = userService.findById(drafterId); Document document = createDocumentRequest.toDocument(drafter); List approvers = findAllUserById(approverIds); - document.enrollApprovals(approvers, document); + document.enrollApprovals(approvers); documentRepository.save(document); } @@ -62,19 +62,20 @@ private List findAllUserById(final List approverIds) { @Transactional(readOnly = true) public SelectDocumentResponse find(final Long documentId) { - Document document = findDocumentAndDrafterById(documentId); + Document document = findDocumentAndDrafterAndDocumentApprovalsById(documentId); List documentApprovalIds = document.getDocumentApprovals() .stream() .map(DocumentApproval::getId) .collect(Collectors.toList()); + List documentApprovals = documentApprovalRepository.findAllDocumentApprovalAndApproverAndTeamByIds(documentApprovalIds); return new SelectDocumentResponse(document, documentApprovals); } - private Document findDocumentAndDrafterById(final Long documentId) { - return documentRepository.findDocumentAndDrafterById(documentId) + private Document findDocumentAndDrafterAndDocumentApprovalsById(final Long documentId) { + return documentRepository.findDocumentAndDrafterAndDocumentApprovalsById(documentId) .orElseThrow(() -> new EntityNotFoundException(String.format("[%d] 식별번호에 해당하는 문서가 존재하지 않습니다.", documentId))); } diff --git a/src/test/java/playground/QueryTest.java b/src/test/java/playground/QueryTest.java new file mode 100644 index 0000000..1bbe4e2 --- /dev/null +++ b/src/test/java/playground/QueryTest.java @@ -0,0 +1,34 @@ +package playground; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.transaction.annotation.Transactional; +import playground.repository.document.DocumentApprovalRepository; +import playground.repository.document.DocumentRepository; +import playground.service.user.UserService; + +@SpringBootTest +@Transactional +public class QueryTest { + + @Autowired + private DocumentApprovalRepository documentApprovalRepository; + + @Autowired + private DocumentRepository documentRepository; + + @Autowired + private UserService userService; + + @Test + @DisplayName("") + void test() { + //given + + //when + + //then + } +} diff --git a/src/test/java/playground/repository/document/DocumentRepositoryTest.java b/src/test/java/playground/repository/document/DocumentRepositoryTest.java index 50b3163..3751ca0 100644 --- a/src/test/java/playground/repository/document/DocumentRepositoryTest.java +++ b/src/test/java/playground/repository/document/DocumentRepositoryTest.java @@ -16,6 +16,7 @@ import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.PersistenceUnitUtil; +import java.util.Collections; import java.util.List; import java.util.Optional; @@ -41,8 +42,8 @@ void setUp() { } @Test - @DisplayName("기안자의 정보가 포함된 문서를 조회한다.") - void findDocumentAndDrafterById() { + @DisplayName("기안자의 정보, 결재 정보 리스트가 포함된 문서를 조회한다.") + void findDocumentAndDrafterAndDocumentApprovalsById() { //given Team team = new Team("정산시스템팀"); entityManager.persist(team); @@ -60,16 +61,18 @@ void findDocumentAndDrafterById() { .title("교육비 정산") .contents("교육비 정산 결재") .build(); + document.enrollApprovals(Collections.singletonList(drafter)); documentRepository.save(document); entityManager.flush(); entityManager.clear(); //when - Optional fetchedDocument = documentRepository.findDocumentAndDrafterById(document.getId()); + Optional fetchedDocument = documentRepository.findDocumentAndDrafterAndDocumentApprovalsById(document.getId()); //then assertThat(fetchedDocument).isNotEmpty(); assertThat(persistenceUnitUtil.isLoaded(fetchedDocument.get().getDrafter())).isTrue(); + assertThat(persistenceUnitUtil.isLoaded(fetchedDocument.get().getDocumentApprovals())).isTrue(); } @Test diff --git a/src/test/java/playground/service/document/DocumentServiceTest.java b/src/test/java/playground/service/document/DocumentServiceTest.java index 06e8c31..31d8c6d 100644 --- a/src/test/java/playground/service/document/DocumentServiceTest.java +++ b/src/test/java/playground/service/document/DocumentServiceTest.java @@ -107,7 +107,7 @@ void find() { given(documentApproval.getApprover()).willReturn(drafter); given(documentApproval.getApprovalState()).willReturn(ApprovalState.DRAFTING); given(documentApprovalRepository.findAllDocumentApprovalAndApproverAndTeamByIds(anyList())).willReturn(Collections.singletonList(documentApproval)); - given(documentRepository.findDocumentAndDrafterById(anyLong())).willReturn(Optional.of(document)); + given(documentRepository.findDocumentAndDrafterAndDocumentApprovalsById(anyLong())).willReturn(Optional.of(document)); //when SelectDocumentResponse selectDocumentResponse = documentService.find(1L);