From e73376ede7fe0f6cd3c8ae4e997d5a62f6027de0 Mon Sep 17 00:00:00 2001 From: bnminji Date: Thu, 23 Dec 2021 23:02:29 +0900 Subject: [PATCH 1/2] =?UTF-8?q?Team=5FWAS=5FYAS=5FBE-233=20[test]=20?= =?UTF-8?q?=EA=B2=8C=EC=8B=9C=ED=8C=90,=20=EB=8C=93=EA=B8=80=20=ED=86=B5?= =?UTF-8?q?=ED=95=A9=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 1 + .../yas/jwt/JwtAuthenticationToken.java | 2 +- .../controller/CommentControllerTest.java | 122 ++++++++++++++++ .../post/controller/PostControllerTest.java | 135 ++++++++++++++++++ .../security/WithMockJwtAuthentication.java | 15 ++ ...tAuthenticationSecurityContextFactory.java | 30 ++++ 6 files changed, 304 insertions(+), 1 deletion(-) create mode 100644 src/test/java/org/prgrms/yas/domain/comment/controller/CommentControllerTest.java create mode 100644 src/test/java/org/prgrms/yas/domain/post/controller/PostControllerTest.java create mode 100644 src/test/java/org/prgrms/yas/setting/security/WithMockJwtAuthentication.java create mode 100644 src/test/java/org/prgrms/yas/setting/security/WithMockJwtAuthenticationSecurityContextFactory.java 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..6f613379 --- /dev/null +++ b/src/test/java/org/prgrms/yas/domain/post/controller/PostControllerTest.java @@ -0,0 +1,135 @@ +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 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.repository.CommentRepository; +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.routine.domain.Routine; +import org.prgrms.yas.domain.user.domain.User; +import org.prgrms.yas.domain.user.repository.UserRepository; +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.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 PostControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private UserSetup userSetup; + + @Autowired + private RoutineSetup routineSetup; + + @Autowired + private PostSetup postSetup; + + @Autowired + private UserRepository userRepository; + + @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; + + //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").isString()) + .andExpect(jsonPath("$.data.updatedAt").isString()) + .andExpect(jsonPath("$.data.content").value("content")) + .andExpect(jsonPath("$.data.user.userId").value(1L)) + .andExpect(jsonPath("$.data.user.nickname").value("nickname")) + .andExpect(jsonPath("$.data.user.profileImage").isEmpty()) + .andExpect(jsonPath("$.data.routine.routineId").value(1L)) + .andExpect(jsonPath("$.data.routine.name").value("routineName")) + .andExpect(jsonPath("$.data.routine.emoji").value("^^")) + .andExpect(jsonPath("$.data.routine.durationGoalTime").value(1)) + .andExpect(jsonPath("$.data.routine.color").value("black")) + .andExpect(jsonPath("$.data.routine.startGoalTime").isNotEmpty()) + .andExpect(jsonPath("$.data.routine.weeks", hasSize(2))) + .andExpect(jsonPath("$.data.routine.category", hasSize(2))) + .andExpect(jsonPath("$.data.routine.missions", hasSize(1))) + .andExpect(jsonPath("$.data.comments", hasSize(1))) + .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; + } +} From b370a80b1b3cba1f8368e28b1b9b12ab47ad664a Mon Sep 17 00:00:00 2001 From: bnminji Date: Fri, 24 Dec 2021 00:16:32 +0900 Subject: [PATCH 2/2] =?UTF-8?q?Refactor=20:=20PostControllerTest=20findOne?= =?UTF-8?q?Test=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../post/controller/PostControllerTest.java | 148 +++++++++++++----- 1 file changed, 113 insertions(+), 35 deletions(-) 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 index 6f613379..f0d73f1a 100644 --- a/src/test/java/org/prgrms/yas/domain/post/controller/PostControllerTest.java +++ b/src/test/java/org/prgrms/yas/domain/post/controller/PostControllerTest.java @@ -9,22 +9,19 @@ 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.comment.domain.Comment; -import org.prgrms.yas.domain.comment.repository.CommentRepository; +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.routine.domain.Routine; -import org.prgrms.yas.domain.user.domain.User; -import org.prgrms.yas.domain.user.repository.UserRepository; +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.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; @@ -49,16 +46,10 @@ class PostControllerTest { private ObjectMapper objectMapper; @Autowired - private UserSetup userSetup; + private PostRepository postRepository; @Autowired - private RoutineSetup routineSetup; - - @Autowired - private PostSetup postSetup; - - @Autowired - private UserRepository userRepository; + private PostLikesRepository postLikesRepository; @Test @DisplayName("게시글등록_테스트") @@ -73,7 +64,7 @@ void createTest() throws Exception { routineId ).contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(postCreateRequest))); - + // then result.andExpect(status().isOk()) .andExpect(jsonPath("$.data").isNumber()); @@ -103,7 +94,9 @@ void deleteTest() throws Exception { 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}", @@ -114,22 +107,107 @@ void findOneTest() throws Exception { result.andExpect(status().isOk()) .andDo(print()) .andExpect(jsonPath("$.data.postId").value(postId)) - .andExpect(jsonPath("$.data.createdAt").isString()) - .andExpect(jsonPath("$.data.updatedAt").isString()) - .andExpect(jsonPath("$.data.content").value("content")) - .andExpect(jsonPath("$.data.user.userId").value(1L)) - .andExpect(jsonPath("$.data.user.nickname").value("nickname")) - .andExpect(jsonPath("$.data.user.profileImage").isEmpty()) - .andExpect(jsonPath("$.data.routine.routineId").value(1L)) - .andExpect(jsonPath("$.data.routine.name").value("routineName")) - .andExpect(jsonPath("$.data.routine.emoji").value("^^")) - .andExpect(jsonPath("$.data.routine.durationGoalTime").value(1)) - .andExpect(jsonPath("$.data.routine.color").value("black")) - .andExpect(jsonPath("$.data.routine.startGoalTime").isNotEmpty()) - .andExpect(jsonPath("$.data.routine.weeks", hasSize(2))) - .andExpect(jsonPath("$.data.routine.category", hasSize(2))) - .andExpect(jsonPath("$.data.routine.missions", hasSize(1))) - .andExpect(jsonPath("$.data.comments", hasSize(1))) - .andExpect(jsonPath("$.data.likes", hasSize(1))); + .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