diff --git a/build.gradle b/build.gradle index 5f61cad7..f0ffb36c 100644 --- a/build.gradle +++ b/build.gradle @@ -16,25 +16,36 @@ repositories { } dependencies { + // basic implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + // query dsl implementation 'com.querydsl:querydsl-jpa' implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.8' + // database runtimeOnly 'com.h2database:h2' - testImplementation 'org.springframework.boot:spring-boot-starter-test' + // test + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation 'io.rest-assured:rest-assured:4.4.0' + testImplementation 'io.rest-assured:json-path:4.4.0' + testImplementation 'io.rest-assured:spring-mock-mvc:4.4.0' testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc' asciidoctor 'org.springframework.restdocs:spring-restdocs-asciidoctor' + // jwt compile group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.2' runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.2' runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.2' } -apply from: 'test.gradle' +apply from: 'jacoco.gradle' def querydslDir = "$buildDir/generated/querydsl" querydsl { @@ -68,7 +79,7 @@ asciidoctor { bootJar { dependsOn asciidoctor - from ("${asciidoctor.outputDir}/html5") { // gradle은 src/docs/asciidoc 에 메인 adoc생성! + from("${asciidoctor.outputDir}/html5") { // gradle은 src/docs/asciidoc 에 메인 adoc생성! into 'static/docs' // asciidoctor로 만든 문서는 static/docs 디렉토리로.! } } diff --git a/test.gradle b/jacoco.gradle similarity index 100% rename from test.gradle rename to jacoco.gradle diff --git a/src/main/java/com/study/realworld/domain/follow/TestAPI.java b/src/main/java/com/study/realworld/domain/follow/TestAPI.java index 96c86d8b..1a8489aa 100644 --- a/src/main/java/com/study/realworld/domain/follow/TestAPI.java +++ b/src/main/java/com/study/realworld/domain/follow/TestAPI.java @@ -2,7 +2,7 @@ import com.study.realworld.domain.follow.application.FollowService; import com.study.realworld.domain.follow.domain.FollowQueryDslRepository; -import com.study.realworld.domain.follow.dto.FollowableDto; +import com.study.realworld.domain.follow.dto.FollowResponse; import com.study.realworld.domain.user.domain.persist.User; import com.study.realworld.domain.user.domain.persist.UserRepository; import org.springframework.http.ResponseEntity; @@ -27,20 +27,20 @@ public TestAPI(final FollowQueryDslRepository queryDslRepository, final UserRepo } @PostMapping("follow/{targetId}") - public ResponseEntity follow(@AuthenticationPrincipal Long id, @PathVariable Long targetId) { + public ResponseEntity follow(@AuthenticationPrincipal Long id, @PathVariable Long targetId) { User user = userRepository.findById(id).get(); User user1 = userRepository.findById(targetId).get(); followService.following(id, targetId); - FollowableDto followableDto = queryDslRepository.existMeAndFollowing(user, user1); - return ResponseEntity.ok().body(followableDto); + FollowResponse followResponse = queryDslRepository.existMeAndFollowing(user, user1); + return ResponseEntity.ok().body(followResponse); } @GetMapping("test/{targetId}") - public ResponseEntity test(@AuthenticationPrincipal Long id, @PathVariable Long targetId) { + public ResponseEntity test(@AuthenticationPrincipal Long id, @PathVariable Long targetId) { User user = userRepository.findById(id).get(); User user1 = userRepository.findById(targetId).get(); - FollowableDto followableDto = queryDslRepository.existMeAndFollowing(user, user1); - return ResponseEntity.ok().body(followableDto); + FollowResponse followResponse = queryDslRepository.existMeAndFollowing(user, user1); + return ResponseEntity.ok().body(followResponse); } } diff --git a/src/main/java/com/study/realworld/domain/follow/application/FollowService.java b/src/main/java/com/study/realworld/domain/follow/application/FollowService.java index 3ece95d7..fdb410f7 100644 --- a/src/main/java/com/study/realworld/domain/follow/application/FollowService.java +++ b/src/main/java/com/study/realworld/domain/follow/application/FollowService.java @@ -3,7 +3,6 @@ import com.study.realworld.domain.follow.domain.Follow; import com.study.realworld.domain.follow.domain.FollowQueryDslRepository; import com.study.realworld.domain.follow.domain.FollowRepository; -import com.study.realworld.domain.follow.dto.FollowableDto; import com.study.realworld.domain.user.domain.persist.User; import com.study.realworld.domain.user.domain.persist.UserRepository; import com.study.realworld.domain.user.error.exception.IdentityNotFoundException; diff --git a/src/main/java/com/study/realworld/domain/follow/domain/FollowQueryDslRepository.java b/src/main/java/com/study/realworld/domain/follow/domain/FollowQueryDslRepository.java index 78e30b70..c4e52534 100644 --- a/src/main/java/com/study/realworld/domain/follow/domain/FollowQueryDslRepository.java +++ b/src/main/java/com/study/realworld/domain/follow/domain/FollowQueryDslRepository.java @@ -4,7 +4,7 @@ import com.querydsl.core.types.Projections; import com.querydsl.jpa.JPAExpressions; import com.querydsl.jpa.impl.JPAQueryFactory; -import com.study.realworld.domain.follow.dto.FollowableDto; +import com.study.realworld.domain.follow.dto.FollowResponse; import com.study.realworld.domain.user.domain.persist.User; import org.springframework.stereotype.Repository; @@ -19,8 +19,8 @@ public FollowQueryDslRepository(final JPAQueryFactory jpaQueryFactory) { this.query = jpaQueryFactory; } - public FollowableDto existMeAndFollowing(final User me, final User following) { - return query.select(Projections.constructor(FollowableDto.class, user, + public FollowResponse existMeAndFollowing(final User me, final User following) { + return query.select(Projections.constructor(FollowResponse.class, user, ExpressionUtils.isNotNull(JPAExpressions.selectOne() .from(follow) .where(follow.following.eq(following), follow.follower.eq(me))))) diff --git a/src/main/java/com/study/realworld/domain/follow/dto/FollowableDto.java b/src/main/java/com/study/realworld/domain/follow/dto/FollowResponse.java similarity index 55% rename from src/main/java/com/study/realworld/domain/follow/dto/FollowableDto.java rename to src/main/java/com/study/realworld/domain/follow/dto/FollowResponse.java index 6664759f..d99f276e 100644 --- a/src/main/java/com/study/realworld/domain/follow/dto/FollowableDto.java +++ b/src/main/java/com/study/realworld/domain/follow/dto/FollowResponse.java @@ -6,7 +6,7 @@ import com.study.realworld.domain.user.domain.vo.Image; import com.study.realworld.domain.user.domain.vo.Name; -public class FollowableDto { +public class FollowResponse { @JsonProperty("username") private Name username; @@ -20,21 +20,14 @@ public class FollowableDto { @JsonProperty("following") private Boolean followable; - public static FollowableDto fromUserAndFollowable(final User me, final boolean followable) { - return new FollowableDto(me.username(), me.bio(), me.image(), followable); + FollowResponse() { } - FollowableDto() { + public FollowResponse(final User me, final boolean followable) { + this(me.username(), me.bio(), me.image(), followable); } - public FollowableDto(final User me, final boolean followable) { - this.username = me.username(); - this.bio = me.bio(); - this.image = me.image(); - this.followable = followable; - } - - private FollowableDto(final Name username, final Bio bio, final Image image, final Boolean followable) { + private FollowResponse(final Name username, final Bio bio, final Image image, final Boolean followable) { this.username = username; this.bio = bio; this.image = image; diff --git a/src/main/java/com/study/realworld/domain/user/application/UserFindService.java b/src/main/java/com/study/realworld/domain/user/application/UserQueryService.java similarity index 67% rename from src/main/java/com/study/realworld/domain/user/application/UserFindService.java rename to src/main/java/com/study/realworld/domain/user/application/UserQueryService.java index c207b922..b06d13a7 100644 --- a/src/main/java/com/study/realworld/domain/user/application/UserFindService.java +++ b/src/main/java/com/study/realworld/domain/user/application/UserQueryService.java @@ -1,34 +1,27 @@ package com.study.realworld.domain.user.application; import com.study.realworld.domain.follow.domain.FollowRepository; -import com.study.realworld.domain.user.domain.vo.Email; import com.study.realworld.domain.user.domain.persist.User; import com.study.realworld.domain.user.domain.persist.UserRepository; +import com.study.realworld.domain.user.domain.vo.Email; import com.study.realworld.domain.user.error.exception.EmailNotFoundException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Transactional(readOnly = true) @Service -public class UserFindService { +public class UserQueryService { private final UserRepository userRepository; - private final FollowRepository followRepository; - public UserFindService(final UserRepository userRepository, final FollowRepository followRepository) { + public UserQueryService(final UserRepository userRepository, final FollowRepository followRepository) { this.userRepository = userRepository; - this.followRepository = followRepository; } public User findUserByEmail(final String email) { return findByEmail(email); } -// public User findProfileByName(final Long id, final Name username) { -// final User user = userRepository.findById(id).orElseThrow(IllegalArgumentException::new); -// return findByEmail(); -// } - private User findByEmail(final String email) { return userRepository.findByEmail(new Email(email)) .orElseThrow(() -> new EmailNotFoundException(email)); diff --git a/src/main/java/com/study/realworld/global/jwt/authentication/JwtAuthenticationProvider.java b/src/main/java/com/study/realworld/global/jwt/authentication/JwtAuthenticationProvider.java index 084c0ade..2f327cc3 100644 --- a/src/main/java/com/study/realworld/global/jwt/authentication/JwtAuthenticationProvider.java +++ b/src/main/java/com/study/realworld/global/jwt/authentication/JwtAuthenticationProvider.java @@ -1,7 +1,7 @@ package com.study.realworld.global.jwt.authentication; import com.study.realworld.domain.auth.infrastructure.TokenProvider; -import com.study.realworld.domain.user.application.UserFindService; +import com.study.realworld.domain.user.application.UserQueryService; import com.study.realworld.domain.user.domain.persist.User; import com.study.realworld.global.security.error.exception.UserDetailsNullPointerException; import org.springframework.security.authentication.AuthenticationProvider; @@ -14,11 +14,11 @@ @Component public class JwtAuthenticationProvider implements AuthenticationProvider { - private final UserFindService userFindService; + private final UserQueryService userQueryService; private final TokenProvider tokenProvider; - public JwtAuthenticationProvider(final UserFindService userFindService, final TokenProvider tokenProvider) { - this.userFindService = userFindService; + public JwtAuthenticationProvider(final UserQueryService userQueryService, final TokenProvider tokenProvider) { + this.userQueryService = userQueryService; this.tokenProvider = tokenProvider; } @@ -35,7 +35,7 @@ private String determineUsername(final Authentication authentication) { } private User retrieveUser(final String email) { - final User user = userFindService.findUserByEmail(email); + final User user = userQueryService.findUserByEmail(email); validateUserDetailsNull(user); return user; } diff --git a/src/test/java/com/study/realworld/domain/follow/domain/FollowQueryDslRepositoryTest.java b/src/test/java/com/study/realworld/domain/follow/domain/FollowQueryDslRepositoryTest.java index 5aaa2e81..0dacd609 100644 --- a/src/test/java/com/study/realworld/domain/follow/domain/FollowQueryDslRepositoryTest.java +++ b/src/test/java/com/study/realworld/domain/follow/domain/FollowQueryDslRepositoryTest.java @@ -1,15 +1,12 @@ package com.study.realworld.domain.follow.domain; import com.querydsl.jpa.impl.JPAQueryFactory; -import com.study.realworld.domain.follow.dto.FollowableDto; +import com.study.realworld.domain.follow.dto.FollowResponse; import com.study.realworld.domain.user.domain.persist.User; import com.study.realworld.domain.user.domain.vo.*; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; @@ -59,11 +56,11 @@ void existMeAndFollowing_test() { // when final FollowQueryDslRepository followQueryDslRepository = new FollowQueryDslRepository(jpaQueryFactory); - final FollowableDto followableDto = followQueryDslRepository.existMeAndFollowing(user, other); + final FollowResponse followResponse = followQueryDslRepository.existMeAndFollowing(user, other); assertAll( - () -> assertThat(followableDto).isNotNull(), - () -> assertThat(followableDto).isExactlyInstanceOf(FollowableDto.class) + () -> assertThat(followResponse).isNotNull(), + () -> assertThat(followResponse).isExactlyInstanceOf(FollowResponse.class) ); } diff --git a/src/test/java/com/study/realworld/domain/follow/dto/FollowableDtoTest.java b/src/test/java/com/study/realworld/domain/follow/dto/FollowResponseTest.java similarity index 72% rename from src/test/java/com/study/realworld/domain/follow/dto/FollowableDtoTest.java rename to src/test/java/com/study/realworld/domain/follow/dto/FollowResponseTest.java index 78180927..b4b43397 100644 --- a/src/test/java/com/study/realworld/domain/follow/dto/FollowableDtoTest.java +++ b/src/test/java/com/study/realworld/domain/follow/dto/FollowResponseTest.java @@ -14,16 +14,16 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.*; -class FollowableDtoTest { +class FollowResponseTest { @DisplayName("FollowableDto 기본 생성자 테스트") @Test void default_constructor_test() { - final FollowableDto followableDto = new FollowableDto(); + final FollowResponse followResponse = new FollowResponse(); assertAll( - () -> assertThat(followableDto).isNotNull(), - () -> assertThat(followableDto).isExactlyInstanceOf(FollowableDto.class) + () -> assertThat(followResponse).isNotNull(), + () -> assertThat(followResponse).isExactlyInstanceOf(FollowResponse.class) ); } @@ -32,11 +32,11 @@ void default_constructor_test() { void fromUserAndFollowable_test() { final User user = userBuilder(new Email(EMAIL), new Name(USERNAME), new Password(PASSWORD), new Bio(BIO), new Image(IMAGE)); final boolean followable = false; - final FollowableDto followableDto = FollowableDto.fromUserAndFollowable(user, followable); + final FollowResponse followResponse = new FollowResponse(user, followable); assertAll( - () -> assertThat(followableDto).isNotNull(), - () -> assertThat(followableDto).isExactlyInstanceOf(FollowableDto.class) + () -> assertThat(followResponse).isNotNull(), + () -> assertThat(followResponse).isExactlyInstanceOf(FollowResponse.class) ); } diff --git a/src/test/java/com/study/realworld/domain/user/application/UserFindServiceTest.java b/src/test/java/com/study/realworld/domain/user/application/UserQueryServiceTest.java similarity index 83% rename from src/test/java/com/study/realworld/domain/user/application/UserFindServiceTest.java rename to src/test/java/com/study/realworld/domain/user/application/UserQueryServiceTest.java index e254cd8c..6b85c3e4 100644 --- a/src/test/java/com/study/realworld/domain/user/application/UserFindServiceTest.java +++ b/src/test/java/com/study/realworld/domain/user/application/UserQueryServiceTest.java @@ -27,20 +27,20 @@ import static org.mockito.BDDMockito.given; @ExtendWith(MockitoExtension.class) -public class UserFindServiceTest { +public class UserQueryServiceTest { @Mock private UserRepository userRepository; @Mock private FollowRepository followRepository; - @InjectMocks private UserFindService userFindService; + @InjectMocks private UserQueryService userQueryService; @DisplayName("JwtUserDetailsService 인스턴스 생성자 테스트") @Test void constructor_test() { - final UserFindService userFindService = new UserFindService(userRepository, followRepository); + final UserQueryService userQueryService = new UserQueryService(userRepository, followRepository); assertAll( - () -> assertThat(userFindService).isNotNull(), - () -> assertThat(userFindService).isInstanceOf(UserFindService.class) + () -> assertThat(userQueryService).isNotNull(), + () -> assertThat(userQueryService).isInstanceOf(UserQueryService.class) ); } @@ -50,7 +50,7 @@ void findByEmail_test() { final User user = userBuilder(new Email(EMAIL), new Name(USERNAME), new Password(PASSWORD), new Bio(BIO), new Image(IMAGE)); given(userRepository.findByEmail(any())).willReturn(Optional.ofNullable(user)); - final User findUser = userFindService.findUserByEmail(EMAIL); + final User findUser = userQueryService.findUserByEmail(EMAIL); assertAll( () -> assertThat(findUser.email().email()).isEqualTo(EMAIL), () -> assertThat(findUser.password().password()).isEqualTo(PASSWORD) @@ -62,7 +62,7 @@ void findByEmail_test() { void fail_findByEmail_test() { given(userRepository.findByEmail(any())).willReturn(Optional.ofNullable(null)); - assertThatThrownBy(() -> userFindService.findUserByEmail(EMAIL)) + assertThatThrownBy(() -> userQueryService.findUserByEmail(EMAIL)) .isInstanceOf(EmailNotFoundException.class) .hasMessage(String.format("이메일 : [ %s ] 를 찾을 수 없습니다.", EMAIL)); } diff --git a/src/test/java/com/study/realworld/global/jwt/JwtAuthenticationProviderTest.java b/src/test/java/com/study/realworld/global/jwt/JwtAuthenticationProviderTest.java index 62f89770..4456b5d9 100644 --- a/src/test/java/com/study/realworld/global/jwt/JwtAuthenticationProviderTest.java +++ b/src/test/java/com/study/realworld/global/jwt/JwtAuthenticationProviderTest.java @@ -1,7 +1,7 @@ package com.study.realworld.global.jwt; import com.study.realworld.domain.auth.infrastructure.TokenProvider; -import com.study.realworld.domain.user.application.UserFindService; +import com.study.realworld.domain.user.application.UserQueryService; import com.study.realworld.domain.user.domain.persist.User; import com.study.realworld.domain.user.domain.vo.*; import com.study.realworld.global.jwt.authentication.JwtAuthentication; @@ -36,13 +36,13 @@ class JwtAuthenticationProviderTest { @Mock private TokenProvider tokenProvider; - @Mock private UserFindService userFindService; + @Mock private UserQueryService userQueryService; @InjectMocks private JwtAuthenticationProvider jwtAuthenticationProvider; @DisplayName("JwtAuthenticationProvider 인스턴스 생성자 테스트") @Test void constructor_test() { - final JwtAuthenticationProvider jwtAuthenticationProvider = new JwtAuthenticationProvider(userFindService, tokenProvider); + final JwtAuthenticationProvider jwtAuthenticationProvider = new JwtAuthenticationProvider(userQueryService, tokenProvider); assertAll( () -> assertThat(jwtAuthenticationProvider).isNotNull(), @@ -60,7 +60,7 @@ void authenticate_test() { final User user = userBuilder(email, new Name(USERNAME), password, new Bio(BIO), new Image(IMAGE)); ReflectionTestUtils.setField(user, "id", 1L); doReturn(USERNAME).when(tokenProvider).mapToUsername(any()); - doReturn(user).when(userFindService).findUserByEmail(any()); + doReturn(user).when(userQueryService).findUserByEmail(any()); final JwtAuthentication jwtAuthentication = initAuthentication(testToken()); final Authentication authenticate = jwtAuthenticationProvider.authenticate(jwtAuthentication); @@ -88,7 +88,7 @@ void supports_test() { @Test void validateUserDetailsNull_test() { doReturn(USERNAME).when(tokenProvider).mapToUsername(any()); - doReturn(null).when(userFindService).findUserByEmail(any()); + doReturn(null).when(userQueryService).findUserByEmail(any()); final JwtAuthentication jwtAuthentication = initAuthentication(testToken()); assertThatThrownBy(() -> jwtAuthenticationProvider.authenticate(jwtAuthenticationProvider.authenticate(jwtAuthentication)))