diff --git a/backend/baton/src/main/java/touch/baton/domain/supporter/controller/SupporterProfileController.java b/backend/baton/src/main/java/touch/baton/domain/supporter/controller/SupporterProfileController.java new file mode 100644 index 000000000..49fb54b40 --- /dev/null +++ b/backend/baton/src/main/java/touch/baton/domain/supporter/controller/SupporterProfileController.java @@ -0,0 +1,27 @@ +package touch.baton.domain.supporter.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import touch.baton.domain.supporter.Supporter; +import touch.baton.domain.supporter.controller.response.SupporterResponse; +import touch.baton.domain.supporter.service.SupporterService; + +@RequiredArgsConstructor +@RequestMapping("/api/v1/profile/supporter") +@RestController +public class SupporterProfileController { + + private final SupporterService supporterService; + + @GetMapping("/{supporterId}") + public ResponseEntity readProfileBySupporterId(@PathVariable final Long supporterId) { + final Supporter foundSupporter = supporterService.readBySupporterId(supporterId); + final SupporterResponse.Profile response = SupporterResponse.Profile.from(foundSupporter); + + return ResponseEntity.ok(response); + } +} diff --git a/backend/baton/src/main/java/touch/baton/domain/supporter/controller/response/SupporterResponse.java b/backend/baton/src/main/java/touch/baton/domain/supporter/controller/response/SupporterResponse.java index b6765c783..b493b5725 100644 --- a/backend/baton/src/main/java/touch/baton/domain/supporter/controller/response/SupporterResponse.java +++ b/backend/baton/src/main/java/touch/baton/domain/supporter/controller/response/SupporterResponse.java @@ -1,7 +1,6 @@ package touch.baton.domain.supporter.controller.response; import touch.baton.domain.supporter.Supporter; -import touch.baton.domain.technicaltag.SupporterTechnicalTag; import java.util.List; @@ -24,16 +23,36 @@ public static Detail from(final Supporter supporter) { supporter.getReviewCount().getValue(), supporter.getMember().getGithubUrl().getValue(), supporter.getIntroduction().getValue(), - getTechnicalTagsName(supporter) + convertToTechnicalTags(supporter) ); } + } - private static List getTechnicalTagsName(final Supporter supporter) { - return supporter.getSupporterTechnicalTags().getSupporterTechnicalTags() - .stream() - .map(SupporterTechnicalTag::getTechnicalTag) - .map(technicalTag -> technicalTag.getTagName().getValue()) - .toList(); + public record Profile(Long supporterId, + String name, + String company, + String imageUrl, + String githubUrl, + String introduction, + List technicalTags + ) { + public static SupporterResponse.Profile from(final Supporter supporter) { + return new SupporterResponse.Profile( + supporter.getId(), + supporter.getMember().getMemberName().getValue(), + supporter.getMember().getCompany().getValue(), + supporter.getMember().getImageUrl().getValue(), + supporter.getMember().getGithubUrl().getValue(), + supporter.getIntroduction().getValue(), + convertToTechnicalTags(supporter) + ); } } + + private static List convertToTechnicalTags(final Supporter supporter) { + return supporter.getSupporterTechnicalTags().getSupporterTechnicalTags() + .stream() + .map(supporterTechnicalTag -> supporterTechnicalTag.getTechnicalTag().getTagName().getValue()) + .toList(); + } } diff --git a/backend/baton/src/main/java/touch/baton/domain/supporter/repository/SupporterRepository.java b/backend/baton/src/main/java/touch/baton/domain/supporter/repository/SupporterRepository.java index cd48a42f7..da9865b8e 100644 --- a/backend/baton/src/main/java/touch/baton/domain/supporter/repository/SupporterRepository.java +++ b/backend/baton/src/main/java/touch/baton/domain/supporter/repository/SupporterRepository.java @@ -1,7 +1,19 @@ package touch.baton.domain.supporter.repository; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import touch.baton.domain.supporter.Supporter; +import java.util.Optional; + public interface SupporterRepository extends JpaRepository { + + @Query(""" + select s + from Supporter s + join fetch Member m on s.member.id = m.id + where s.id = :supporterId + """) + Optional joinMemberBySupporterId(@Param("supporterId") final Long supporterId); } diff --git a/backend/baton/src/main/java/touch/baton/domain/supporter/service/SupporterService.java b/backend/baton/src/main/java/touch/baton/domain/supporter/service/SupporterService.java index be8eed7bd..d093c7803 100644 --- a/backend/baton/src/main/java/touch/baton/domain/supporter/service/SupporterService.java +++ b/backend/baton/src/main/java/touch/baton/domain/supporter/service/SupporterService.java @@ -4,6 +4,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import touch.baton.domain.supporter.Supporter; +import touch.baton.domain.supporter.exception.SupporterBusinessException; import touch.baton.domain.supporter.repository.SupporterRepository; import java.util.List; @@ -18,4 +19,9 @@ public class SupporterService { public List readAllSupporters() { return supporterRepository.findAll(); } + + public Supporter readBySupporterId(final Long supporterId) { + return supporterRepository.joinMemberBySupporterId(supporterId) + .orElseThrow(() -> new SupporterBusinessException("존재하지 않는 서포터 식별자값으로 조회할 수 없습니다.")); + } } diff --git a/backend/baton/src/test/java/touch/baton/assure/common/AssuredSupport.java b/backend/baton/src/test/java/touch/baton/assure/common/AssuredSupport.java index ad2996025..7e0efa533 100644 --- a/backend/baton/src/test/java/touch/baton/assure/common/AssuredSupport.java +++ b/backend/baton/src/test/java/touch/baton/assure/common/AssuredSupport.java @@ -19,6 +19,21 @@ public static ExtractableResponse post(final String uri, final Object .extract(); } + public static ExtractableResponse get(final String uri, + final String pathParamName, + final Long id, + final String accessToken + ) { + return RestAssured + .given().log().ifValidationFails() + .auth().preemptive().oauth2(accessToken) + .when().log().ifValidationFails() + .pathParam(pathParamName, id) + .get(uri) + .then().log().ifError() + .extract(); + } + public static ExtractableResponse get(final String uri, final String pathParamName, final Long id) { return RestAssured .given().log().ifValidationFails() @@ -32,7 +47,7 @@ public static ExtractableResponse get(final String uri, final String p public static ExtractableResponse get(final String uri, final String accessToken) { return RestAssured .given().log().ifValidationFails() - .header("authorization", "Bearer " + accessToken) + .auth().preemptive().oauth2(accessToken) .when().log().ifValidationFails() .get(uri) .then().log().ifError() diff --git a/backend/baton/src/test/java/touch/baton/assure/runnerpost/RunnerPostAssuredReadTest.java b/backend/baton/src/test/java/touch/baton/assure/runnerpost/RunnerPostAssuredReadTest.java index 57d7fb56e..4174d884e 100644 --- a/backend/baton/src/test/java/touch/baton/assure/runnerpost/RunnerPostAssuredReadTest.java +++ b/backend/baton/src/test/java/touch/baton/assure/runnerpost/RunnerPostAssuredReadTest.java @@ -1,6 +1,5 @@ package touch.baton.assure.runnerpost; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import touch.baton.config.AssuredTestConfig; import touch.baton.domain.member.Member; @@ -23,25 +22,29 @@ @SuppressWarnings("NonAsciiCharacters") class RunnerPostAssuredReadTest extends AssuredTestConfig { - @Disabled @Test void 러너의_게시글_식별자값으로_러너_게시글_상세_정보_조회에_성공한다() { - final Member memberHyena = memberRepository.save(MemberFixture.createHyena()); - final Runner runnerHyena = runnerRepository.save(RunnerFixture.create(introduction("안녕하세요"), memberHyena)); - final RunnerPost runnerPost = runnerPostRepository.save(RunnerPostFixture.create(runnerHyena, deadline(LocalDateTime.now().plusHours(100)))); + final Member 사용자_헤나 = memberRepository.save(MemberFixture.createHyena()); + final Runner 러너_헤나 = runnerRepository.save(RunnerFixture.create(introduction("안녕하세요"), 사용자_헤나)); + final RunnerPost 러너_게시글 = runnerPostRepository.save(RunnerPostFixture.create(러너_헤나, deadline(LocalDateTime.now().plusHours(100)))); + final String 로그인용_토큰 = login(사용자_헤나.getSocialId().getValue()); RunnerPostAssuredSupport - .클라이언트_요청().러너_게시글_식별자값으로_러너_게시글을_조회한다(runnerPost.getId()) - .서버_응답().러너_게시글_단건_조회_성공을_검증한다(new RunnerPostResponse.Detail( - runnerPost.getId(), - runnerPost.getTitle().getValue(), - runnerPost.getContents().getValue(), - runnerPost.getPullRequestUrl().getValue(), - runnerPost.getDeadline().getValue(), + .클라이언트_요청() + .토큰으로_로그인한다(로그인용_토큰) + .러너_게시글_식별자값으로_러너_게시글을_조회한다(러너_게시글.getId()) + + .서버_응답() + .러너_게시글_단건_조회_성공을_검증한다(new RunnerPostResponse.Detail( + 러너_게시글.getId(), + 러너_게시글.getTitle().getValue(), + 러너_게시글.getContents().getValue(), + 러너_게시글.getPullRequestUrl().getValue(), + 러너_게시글.getDeadline().getValue(), watchedCount(1).getValue(), ReviewStatus.NOT_STARTED, true, - RunnerResponse.Detail.from(runnerHyena), + RunnerResponse.Detail.from(러너_헤나), Collections.emptyList() )); } diff --git a/backend/baton/src/test/java/touch/baton/assure/runnerpost/RunnerPostAssuredSupport.java b/backend/baton/src/test/java/touch/baton/assure/runnerpost/RunnerPostAssuredSupport.java index a2fa8aecc..f33108401 100644 --- a/backend/baton/src/test/java/touch/baton/assure/runnerpost/RunnerPostAssuredSupport.java +++ b/backend/baton/src/test/java/touch/baton/assure/runnerpost/RunnerPostAssuredSupport.java @@ -22,8 +22,15 @@ public static class RunnerPostClientRequestBuilder { private ExtractableResponse response; + private String accessToken; + + public RunnerPostClientRequestBuilder 토큰으로_로그인한다(final String accessToken) { + this.accessToken = accessToken; + return this; + } + public RunnerPostClientRequestBuilder 러너_게시글_식별자값으로_러너_게시글을_조회한다(final Long 러너_게시글_식별자값) { - response = AssuredSupport.get("/api/v1/posts/runner/{runnerPostId}", "runnerPostId", 러너_게시글_식별자값); + response = AssuredSupport.get("/api/v1/posts/runner/{runnerPostId}", "runnerPostId", 러너_게시글_식별자값, accessToken); return this; } diff --git a/backend/baton/src/test/java/touch/baton/assure/supporter/SupporterProfileAssuredReadTest.java b/backend/baton/src/test/java/touch/baton/assure/supporter/SupporterProfileAssuredReadTest.java new file mode 100644 index 000000000..d77efa7f6 --- /dev/null +++ b/backend/baton/src/test/java/touch/baton/assure/supporter/SupporterProfileAssuredReadTest.java @@ -0,0 +1,27 @@ +package touch.baton.assure.supporter; + +import org.junit.jupiter.api.Test; +import touch.baton.config.AssuredTestConfig; +import touch.baton.domain.member.Member; +import touch.baton.domain.supporter.Supporter; +import touch.baton.fixture.domain.MemberFixture; +import touch.baton.fixture.domain.SupporterFixture; + +import static touch.baton.assure.supporter.SupporterProfileAssuredSupport.서포터_프로필_응답; + +@SuppressWarnings("NonAsciiCharacters") +class SupporterProfileAssuredReadTest extends AssuredTestConfig { + + @Test + void 서포터_프로필을_조회한다() { + final Member 사용자_헤나 = memberRepository.save(MemberFixture.createHyena()); + final Supporter 서포터_헤나 = supporterRepository.save(SupporterFixture.create(사용자_헤나)); + + SupporterProfileAssuredSupport + .클라이언트_요청() + .서포터_프로필을_서포터_식별자값으로_조회한다(서포터_헤나.getId()) + + .서버_응답() + .서포터_프로필_조회_성공을_검증한다(서포터_프로필_응답(서포터_헤나)); + } +} diff --git a/backend/baton/src/test/java/touch/baton/assure/supporter/SupporterProfileAssuredSupport.java b/backend/baton/src/test/java/touch/baton/assure/supporter/SupporterProfileAssuredSupport.java new file mode 100644 index 000000000..034a2898a --- /dev/null +++ b/backend/baton/src/test/java/touch/baton/assure/supporter/SupporterProfileAssuredSupport.java @@ -0,0 +1,61 @@ +package touch.baton.assure.supporter; + +import io.restassured.response.ExtractableResponse; +import io.restassured.response.Response; +import touch.baton.assure.common.AssuredSupport; +import touch.baton.domain.supporter.Supporter; +import touch.baton.domain.supporter.controller.response.SupporterResponse; + +import static org.assertj.core.api.SoftAssertions.assertSoftly; + +public class SupporterProfileAssuredSupport { + + private SupporterProfileAssuredSupport() { + } + + public static SupporterClientRequestBuilder 클라이언트_요청() { + return new SupporterClientRequestBuilder(); + } + + public static SupporterResponse.Profile 서포터_프로필_응답(final Supporter 서포터) { + return SupporterResponse.Profile.from(서포터); + } + + public static class SupporterClientRequestBuilder { + + private ExtractableResponse response; + + public SupporterClientRequestBuilder 서포터_프로필을_서포터_식별자값으로_조회한다(final Long 서포터_식별자값) { + response = AssuredSupport.get("/api/v1/profile/supporter/{supporterId}", "supporterId", 서포터_식별자값); + return this; + } + + public SupporterServerResponseBuilder 서버_응답() { + return new SupporterServerResponseBuilder(response); + } + } + + public static class SupporterServerResponseBuilder { + + private final ExtractableResponse response; + + public SupporterServerResponseBuilder(final ExtractableResponse response) { + this.response = response; + } + + public void 서포터_프로필_조회_성공을_검증한다(final SupporterResponse.Profile 서포터_프로필_응답) { + final SupporterResponse.Profile actual = this.response.as(SupporterResponse.Profile.class); + + assertSoftly(softly -> { + softly.assertThat(actual.supporterId()).isEqualTo(서포터_프로필_응답.supporterId()); + softly.assertThat(actual.name()).isEqualTo(서포터_프로필_응답.name()); + softly.assertThat(actual.company()).isEqualTo(서포터_프로필_응답.company()); + softly.assertThat(actual.imageUrl()).isEqualTo(서포터_프로필_응답.imageUrl()); + softly.assertThat(actual.githubUrl()).isEqualTo(서포터_프로필_응답.githubUrl()); + softly.assertThat(actual.introduction()).isEqualTo(서포터_프로필_응답.introduction()); + softly.assertThat(actual.technicalTags()).isEqualTo(서포터_프로필_응답.technicalTags()); + } + ); + } + } +} diff --git a/backend/baton/src/test/java/touch/baton/config/AssuredTestConfig.java b/backend/baton/src/test/java/touch/baton/config/AssuredTestConfig.java index e1655292c..ac7adb3ce 100644 --- a/backend/baton/src/test/java/touch/baton/config/AssuredTestConfig.java +++ b/backend/baton/src/test/java/touch/baton/config/AssuredTestConfig.java @@ -1,16 +1,24 @@ package touch.baton.config; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; import io.restassured.RestAssured; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.web.server.LocalServerPort; import touch.baton.domain.member.repository.MemberRepository; import touch.baton.domain.runner.repository.RunnerRepository; import touch.baton.domain.runnerpost.repository.RunnerPostRepository; import touch.baton.domain.supporter.repository.SupporterRepository; +import touch.baton.infra.auth.jwt.JwtDecoder; + +import java.util.UUID; + +import static org.mockito.BDDMockito.when; @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @@ -28,8 +36,21 @@ public abstract class AssuredTestConfig { @Autowired protected SupporterRepository supporterRepository; + @MockBean + private JwtDecoder jwtDecoder; + @BeforeEach void assuredTestSetUp(@LocalServerPort int port) { RestAssured.port = port; } + + public String login(final String socialId) { + final String token = UUID.randomUUID().toString(); + final Claims claims = Jwts.claims(); + claims.put("socialId", socialId); + + when(jwtDecoder.parseJwtToken(token)).thenReturn(claims); + + return token; + } } diff --git a/backend/baton/src/test/java/touch/baton/document/profile/supporter/read/SupporterProfileReadApiTest.java b/backend/baton/src/test/java/touch/baton/document/profile/supporter/read/SupporterProfileReadApiTest.java new file mode 100644 index 000000000..9ff60f604 --- /dev/null +++ b/backend/baton/src/test/java/touch/baton/document/profile/supporter/read/SupporterProfileReadApiTest.java @@ -0,0 +1,71 @@ +package touch.baton.document.profile.supporter.read; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import touch.baton.config.MockMvcTest; +import touch.baton.config.RestdocsConfig; +import touch.baton.domain.supporter.Supporter; +import touch.baton.domain.supporter.controller.SupporterProfileController; +import touch.baton.domain.supporter.service.SupporterService; +import touch.baton.domain.technicaltag.TechnicalTag; +import touch.baton.fixture.domain.MemberFixture; +import touch.baton.fixture.domain.SupporterFixture; +import touch.baton.fixture.domain.TechnicalTagFixture; + +import java.util.List; + +import static org.mockito.BDDMockito.when; +import static org.mockito.Mockito.spy; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.payload.JsonFieldType.ARRAY; +import static org.springframework.restdocs.payload.JsonFieldType.NUMBER; +import static org.springframework.restdocs.payload.JsonFieldType.STRING; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static touch.baton.fixture.vo.ReviewCountFixture.reviewCount; +import static touch.baton.fixture.vo.TagNameFixture.tagName; + +@MockMvcTest(SupporterProfileController.class) +class SupporterProfileReadApiTest extends RestdocsConfig { + + @MockBean + protected SupporterService supporterService; + + @DisplayName("서포터 프로필 조회 API") + @Test + void readProfileBySupporterId() throws Exception { + // given + final TechnicalTag java = TechnicalTagFixture.create(tagName("java")); + final TechnicalTag spring = TechnicalTagFixture.create(tagName("spring")); + final Supporter supporter = SupporterFixture.create(reviewCount(0), MemberFixture.createHyena(), List.of(java, spring)); + final Supporter spySupporter = spy(supporter); + + when(spySupporter.getId()).thenReturn(1L); + when(supporterService.readBySupporterId(spySupporter.getId())).thenReturn(spySupporter); + + // then + mockMvc.perform(get("/api/v1/profile/supporter/{supporterId}", 1L)) + .andExpect(status().isOk()) + .andDo(restDocs.document( + pathParameters( + parameterWithName("supporterId").description("서포터 식별자값") + ), + responseFields( + fieldWithPath("supporterId").type(NUMBER).description("서포터 식별자값"), + fieldWithPath("name").type(STRING).description("서포터 이름"), + fieldWithPath("company").type(STRING).description("서포터 소속 회사"), + fieldWithPath("imageUrl").type(STRING).description("서포터 프로필 이미지 url"), + fieldWithPath("githubUrl").type(STRING).description("서포터 깃허브 url"), + fieldWithPath("introduction").type(STRING).description("서포터 자기소개"), + fieldWithPath("technicalTags").type(ARRAY).description("서포터 기술 태그 목록") + ) + )) + .andDo(print()); + } + +} diff --git a/backend/baton/src/test/java/touch/baton/domain/supporter/repository/SupporterRepositoryTest.java b/backend/baton/src/test/java/touch/baton/domain/supporter/repository/SupporterRepositoryTest.java new file mode 100644 index 000000000..7f1d1c9ce --- /dev/null +++ b/backend/baton/src/test/java/touch/baton/domain/supporter/repository/SupporterRepositoryTest.java @@ -0,0 +1,47 @@ +package touch.baton.domain.supporter.repository; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import touch.baton.config.RepositoryTestConfig; +import touch.baton.domain.member.Member; +import touch.baton.domain.member.repository.MemberRepository; +import touch.baton.domain.supporter.Supporter; +import touch.baton.fixture.domain.MemberFixture; +import touch.baton.fixture.domain.SupporterFixture; + +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +class SupporterRepositoryTest extends RepositoryTestConfig { + + @Autowired + private MemberRepository memberRepository; + + @Autowired + private SupporterRepository supporterRepository; + + @DisplayName("Supporter 식별자값으로 Member 를 패치 조인하여 조회한다.") + @Test + void joinMemberBySupporterId() { + // given + final Member savedMember = memberRepository.save(MemberFixture.createHyena()); + final Supporter savedSupporter = supporterRepository.save(SupporterFixture.create(savedMember)); + + // when + final Optional maybeSupporter = supporterRepository.joinMemberBySupporterId(savedSupporter.getId()); + + // then + assertAll( + () -> assertThat(maybeSupporter).isPresent(), + () -> assertThat(maybeSupporter.get().getId()).isEqualTo(savedSupporter.getId()), + () -> assertThat(maybeSupporter.get().getIntroduction()).isEqualTo(savedSupporter.getIntroduction()), + () -> assertThat(maybeSupporter.get().getReviewCount()).isEqualTo(savedSupporter.getReviewCount()), + () -> assertThat(maybeSupporter.get().getSupporterTechnicalTags()).isEqualTo(savedSupporter.getSupporterTechnicalTags()), + () -> assertThat(maybeSupporter.get().getMember()).isEqualTo(savedMember) + ); + + } +} diff --git a/backend/baton/src/test/java/touch/baton/domain/supporter/service/SupporterServiceTest.java b/backend/baton/src/test/java/touch/baton/domain/supporter/service/SupporterServiceTest.java new file mode 100644 index 000000000..7686b33f4 --- /dev/null +++ b/backend/baton/src/test/java/touch/baton/domain/supporter/service/SupporterServiceTest.java @@ -0,0 +1,44 @@ +package touch.baton.domain.supporter.service; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import touch.baton.config.ServiceTestConfig; +import touch.baton.domain.member.Member; +import touch.baton.domain.supporter.Supporter; +import touch.baton.fixture.domain.MemberFixture; +import touch.baton.fixture.domain.SupporterFixture; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + + +class SupporterServiceTest extends ServiceTestConfig { + + private SupporterService supporterService; + + @BeforeEach + void setUp() { + supporterService = new SupporterService(supporterRepository); + } + + @DisplayName("Supporter 식별자 값으로 Member 패치 조인하여 Supporte 를 조회한다.") + @Test + void readBySupporterId() { + // given + final Member savedMember = memberRepository.save(MemberFixture.createHyena()); + final Supporter savedSupporter = supporterRepository.save(SupporterFixture.create(savedMember)); + + // when + final Supporter foundSupporter = supporterService.readBySupporterId(savedSupporter.getId()); + + // then + assertAll( + () -> assertThat(foundSupporter.getId()).isEqualTo(savedSupporter.getId()), + () -> assertThat(foundSupporter.getIntroduction()).isEqualTo(savedSupporter.getIntroduction()), + () -> assertThat(foundSupporter.getReviewCount()).isEqualTo(savedSupporter.getReviewCount()), + () -> assertThat(foundSupporter.getSupporterTechnicalTags()).isEqualTo(savedSupporter.getSupporterTechnicalTags()), + () -> assertThat(foundSupporter.getMember()).isEqualTo(savedMember) + ); + } +}