diff --git a/build.gradle b/build.gradle index 80f146a5..e0c3cef2 100644 --- a/build.gradle +++ b/build.gradle @@ -51,6 +51,7 @@ dependencies { implementation group: 'org.springframework.cloud', name: 'spring-cloud-starter-aws', version: '2.2.6.RELEASE' testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation 'org.springframework.security:spring-security-test' } test { diff --git a/src/main/java/org/prgrms/yas/jwt/JwtAuthenticationToken.java b/src/main/java/org/prgrms/yas/jwt/JwtAuthenticationToken.java index 9d75bc65..3f19ffa6 100644 --- a/src/main/java/org/prgrms/yas/jwt/JwtAuthenticationToken.java +++ b/src/main/java/org/prgrms/yas/jwt/JwtAuthenticationToken.java @@ -17,7 +17,7 @@ public JwtAuthenticationToken(String principal, String credentials) { this.credentials = credentials; } - JwtAuthenticationToken( + public JwtAuthenticationToken( Object principal, String credentials, Collection authorities ) { super(authorities); diff --git a/src/test/java/org/prgrms/yas/domain/comment/controller/CommentControllerTest.java b/src/test/java/org/prgrms/yas/domain/comment/controller/CommentControllerTest.java new file mode 100644 index 00000000..3f7887ca --- /dev/null +++ b/src/test/java/org/prgrms/yas/domain/comment/controller/CommentControllerTest.java @@ -0,0 +1,122 @@ +package org.prgrms.yas.domain.comment.controller; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.prgrms.yas.domain.comment.domain.Comment; +import org.prgrms.yas.domain.comment.dto.CommentCreateRequest; +import org.prgrms.yas.domain.comment.dto.CommentUpdateRequest; +import org.prgrms.yas.domain.comment.exception.NotFoundCommentException; +import org.prgrms.yas.domain.comment.repository.CommentRepository; +import org.prgrms.yas.domain.post.domain.RoutinePost; +import org.prgrms.yas.domain.routine.domain.Routine; +import org.prgrms.yas.domain.user.domain.User; +import org.prgrms.yas.global.aws.S3Uploader; +import org.prgrms.yas.global.error.ErrorCode; +import org.prgrms.yas.setting.security.WithMockJwtAuthentication; +import org.prgrms.yas.setting.setup.CommentSetup; +import org.prgrms.yas.setting.setup.PostSetup; +import org.prgrms.yas.setting.setup.RoutineSetup; +import org.prgrms.yas.setting.setup.UserSetup; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.transaction.annotation.Transactional; + +@SpringBootTest +@AutoConfigureMockMvc +@Transactional +@Import(S3Uploader.class) +@ActiveProfiles("test") +class CommentControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private UserSetup userSetup; + + @Autowired + private RoutineSetup routineSetup; + + @Autowired + private PostSetup postSetup; + + @Autowired + private CommentSetup commentSetup; + + @Autowired + private CommentRepository commentRepository; + + @Test + @DisplayName("댓글등록_테스트") + @WithMockJwtAuthentication + void createTest() throws Exception { + //given + Long postId = 1L; + CommentCreateRequest commentCreateRequest = new CommentCreateRequest("comment"); + //when + ResultActions result = mockMvc.perform(post( + "/posts/{id}/comments", + postId + ).contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(commentCreateRequest))); + + // then + result.andExpect(status().isOk()) + .andExpect(jsonPath("$.data").isNumber()); + } + + @Test + @DisplayName("댓글수정_테스트") + @WithMockJwtAuthentication + void updateTest() throws Exception { + //given + Long commentId = 1L; + CommentUpdateRequest commentUpdateRequest = new CommentUpdateRequest("commentUpdate"); + + //when + ResultActions result = mockMvc.perform(patch( + "/comments/{id}", + commentId + ).contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(commentUpdateRequest))); + + //then + result.andExpect(status().isOk()) + .andDo(print()) + .andExpect(jsonPath("$.data").value(commentId)); + } + + @Test + @DisplayName("댓글삭제_테스트") + @WithMockJwtAuthentication + void deleteTest() throws Exception { + //given + Long commentId = 1L; + //when + ResultActions result = mockMvc.perform(delete( + "/comments/{id}", + commentId + ).contentType(MediaType.APPLICATION_JSON)); + //then + result.andExpect(status().isOk()) + .andDo(print()) + .andExpect(jsonPath("$.data").value(commentId)); + } +} \ No newline at end of file diff --git a/src/test/java/org/prgrms/yas/domain/post/controller/PostControllerTest.java b/src/test/java/org/prgrms/yas/domain/post/controller/PostControllerTest.java new file mode 100644 index 00000000..f0d73f1a --- /dev/null +++ b/src/test/java/org/prgrms/yas/domain/post/controller/PostControllerTest.java @@ -0,0 +1,213 @@ +package org.prgrms.yas.domain.post.controller; + +import static org.hamcrest.Matchers.hasSize; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.time.format.DateTimeFormatter; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.prgrms.yas.domain.likes.dto.LikesResponse; +import org.prgrms.yas.domain.likes.repository.PostLikesRepository; +import org.prgrms.yas.domain.post.domain.RoutinePost; +import org.prgrms.yas.domain.post.dto.PostCreateRequest; +import org.prgrms.yas.domain.post.exception.NotFoundRoutinePostException; +import org.prgrms.yas.domain.post.repository.PostRepository; +import org.prgrms.yas.global.aws.S3Uploader; +import org.prgrms.yas.global.error.ErrorCode; +import org.prgrms.yas.setting.security.WithMockJwtAuthentication; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.transaction.annotation.Transactional; + +@SpringBootTest +@AutoConfigureMockMvc +@Transactional +@Import(S3Uploader.class) +@ActiveProfiles("test") +class PostControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private PostRepository postRepository; + + @Autowired + private PostLikesRepository postLikesRepository; + + @Test + @DisplayName("게시글등록_테스트") + @WithMockJwtAuthentication + void createTest() throws Exception { + //given + PostCreateRequest postCreateRequest = new PostCreateRequest("post"); + Long routineId = 1L; + //when + ResultActions result = mockMvc.perform(post( + "/routines/{id}/posts", + routineId + ).contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(postCreateRequest))); + + // then + result.andExpect(status().isOk()) + .andExpect(jsonPath("$.data").isNumber()); + } + + + @Test + @DisplayName("게시글삭제_테스트") + @WithMockJwtAuthentication + void deleteTest() throws Exception { + //given + Long postId = 1L; + //when + ResultActions result = mockMvc.perform(delete( + "/posts/{id}", + postId + ).contentType(MediaType.APPLICATION_JSON)); + + //then + result.andExpect(status().isOk()) + .andDo(print()) + .andExpect(jsonPath("$.data").value(postId)); + } + + @Test + @DisplayName("게시글단건조회_테스트") + void findOneTest() throws Exception { + //given + Long postId = 1L; + RoutinePost routinePost = postRepository.findById(postId) + .orElseThrow(() -> new NotFoundRoutinePostException(ErrorCode.NOT_FOUND_RESOURCE_ERROR)); + List likes = postLikesRepository.getByPost(postId); + //when + ResultActions result = mockMvc.perform(get( + "/posts/{id}", + postId + ).contentType(MediaType.APPLICATION_JSON)); + + //then + result.andExpect(status().isOk()) + .andDo(print()) + .andExpect(jsonPath("$.data.postId").value(postId)) + .andExpect(jsonPath("$.data.createdAt").value(routinePost.getCreatedAt().plusHours(9).format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss")))) + .andExpect(jsonPath("$.data.updatedAt").value(routinePost.getUpdatedAt().plusHours(9).format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss")))) + .andExpect(jsonPath("$.data.content").value(routinePost.getContent())) + .andExpect(jsonPath("$.data.user.userId").value(routinePost.getRoutine() + .getUser() + .getId())) + .andExpect(jsonPath("$.data.user.nickname").value(routinePost.getRoutine() + .getUser() + .getNickname())) + .andExpect(jsonPath("$.data.user.profileImage").value(routinePost.getRoutine() + .getUser() + .getProfileImage())) + .andExpect(jsonPath("$.data.routine.routineId").value(routinePost.getRoutine() + .getId())) + .andExpect(jsonPath("$.data.routine.name").value(routinePost.getRoutine() + .getName())) + .andExpect(jsonPath("$.data.routine.emoji").value(routinePost.getRoutine() + .getEmoji())) + .andExpect(jsonPath("$.data.routine.durationGoalTime").value(routinePost.getRoutine() + .getDurationGoalTime())) + .andExpect(jsonPath("$.data.routine.color").value(routinePost.getRoutine() + .getColor())) + .andExpect(jsonPath("$.data.routine.startGoalTime").value(routinePost.getRoutine() + .getStartGoalTime() + .format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX")))) + .andExpect(jsonPath("$.data.routine.weeks[0]").value(routinePost.getRoutine() + .getWeeks() + .get(0) + .toString())) + .andExpect(jsonPath("$.data.routine.weeks[1]").value(routinePost.getRoutine() + .getWeeks() + .get(1) + .toString())) + .andExpect(jsonPath( + "$.data.routine.weeks", + hasSize(2) + )) + .andExpect(jsonPath("$.data.routine.category[0]").value(routinePost.getRoutine() + .getRoutineCategory() + .get(0) + .toString())) + .andExpect(jsonPath("$.data.routine.category[1]").value(routinePost.getRoutine() + .getRoutineCategory() + .get(1) + .toString())) + .andExpect(jsonPath( + "$.data.routine.category", + hasSize(2) + )) + .andExpect(jsonPath("$.data.comments[0].commentId").value(routinePost.getComments() + .get(0) + .getId())) + .andExpect(jsonPath("$.data.comments[0].user.userId").value(routinePost.getComments() + .get(0) + .getUser() + .getId())) + .andExpect(jsonPath("$.data.comments[0].user.nickname").value(routinePost.getComments() + .get(0) + .getUser() + .getNickname())) + .andExpect(jsonPath("$.data.comments[0].user.profileImage").value(routinePost.getComments() + .get(0) + .getUser() + .getProfileImage())) + .andExpect(jsonPath("$.data.comments[0].createdAt").value(routinePost.getComments() + .get(0) + .getCreatedAt() + .format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX")))) + .andExpect(jsonPath("$.data.comments[0].updatedAt").value(routinePost.getComments() + .get(0) + .getUpdatedAt() + .format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX")))) + .andExpect(jsonPath("$.data.comments[0].content").value(routinePost.getComments() + .get(0) + .getContent())) + .andExpect(jsonPath("$.data.comments[0].likes[0].userId").value(routinePost.getComments() + .get(0) + .getCommentLikes() + .get(0) + .getUser() + .getId())) + .andExpect(jsonPath("$.data.comments[0].likes[0].username").value(routinePost.getComments() + .get(0) + .getCommentLikes() + .get(0) + .getUser() + .getNickname())) + .andExpect(jsonPath( + "$.data.comments[0].likes", + hasSize(1) + )) + .andExpect(jsonPath( + "$.data.comments", + hasSize(1) + )) + .andExpect(jsonPath("$.data.likes[0].userId").value(likes.get(0) + .getUserId())) + .andExpect(jsonPath( + "$.data.likes", + hasSize(1) + )); + + } +} \ No newline at end of file diff --git a/src/test/java/org/prgrms/yas/setting/security/WithMockJwtAuthentication.java b/src/test/java/org/prgrms/yas/setting/security/WithMockJwtAuthentication.java new file mode 100644 index 00000000..2ab7128e --- /dev/null +++ b/src/test/java/org/prgrms/yas/setting/security/WithMockJwtAuthentication.java @@ -0,0 +1,15 @@ +package org.prgrms.yas.setting.security; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import org.prgrms.yas.domain.user.domain.Role; +import org.springframework.security.test.context.support.WithSecurityContext; + +@Retention(RetentionPolicy.RUNTIME) +@WithSecurityContext(factory = WithMockJwtAuthenticationSecurityContextFactory.class) +public @interface WithMockJwtAuthentication { + long id() default 1L; + String token() default "testToken"; + String username() default "testName"; + String role() default "USER"; +} diff --git a/src/test/java/org/prgrms/yas/setting/security/WithMockJwtAuthenticationSecurityContextFactory.java b/src/test/java/org/prgrms/yas/setting/security/WithMockJwtAuthenticationSecurityContextFactory.java new file mode 100644 index 00000000..f050b970 --- /dev/null +++ b/src/test/java/org/prgrms/yas/setting/security/WithMockJwtAuthenticationSecurityContextFactory.java @@ -0,0 +1,30 @@ +package org.prgrms.yas.setting.security; + + +import static org.springframework.security.core.authority.AuthorityUtils.createAuthorityList; + +import org.prgrms.yas.jwt.JwtAuthentication; +import org.prgrms.yas.jwt.JwtAuthenticationToken; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.test.context.support.WithSecurityContextFactory; + +public class WithMockJwtAuthenticationSecurityContextFactory implements WithSecurityContextFactory { + + @Override + public SecurityContext createSecurityContext( + WithMockJwtAuthentication annotation + ) { + SecurityContext context = SecurityContextHolder.createEmptyContext(); + JwtAuthenticationToken authentication = new JwtAuthenticationToken( + new JwtAuthentication(annotation.id(), + annotation.token(), + annotation.username() + ), + null, + createAuthorityList(annotation.role()) + ); + context.setAuthentication(authentication); + return context; + } +}