Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor | CAKK-58 | User 비즈니스에 Facade 패턴 적용 #197

Merged
merged 4 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
import com.cakk.common.enums.ReturnCode;
import com.cakk.common.exception.CakkException;
import com.cakk.domain.mysql.entity.user.User;
import com.cakk.domain.mysql.facade.user.UserCommandFacade;
import com.cakk.domain.mysql.repository.reader.UserReader;
import com.cakk.domain.mysql.repository.writer.UserWriter;
import com.cakk.domain.redis.repository.TokenRedisRepository;

@Service
Expand All @@ -26,13 +26,13 @@ public class SignService {
private final JwtProvider jwtProvider;

private final UserReader userReader;
private final UserWriter userWriter;
private final UserCommandFacade userCommandFacade;
private final TokenRedisRepository tokenRedisRepository;

@Transactional
public JwtResponse signUp(final UserSignUpRequest dto) {
final String providerId = oidcProviderFactory.getProviderId(dto.provider(), dto.idToken());
final User user = userWriter.create(UserMapper.supplyUserBy(dto, providerId));
final User user = userCommandFacade.create(UserMapper.supplyUserBy(dto, providerId));

return JwtResponse.from(jwtProvider.generateToken(user));
}
Expand Down
20 changes: 5 additions & 15 deletions cakk-api/src/main/java/com/cakk/api/service/user/UserService.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,15 @@
import com.cakk.domain.mysql.dto.param.user.ProfileUpdateParam;
import com.cakk.domain.mysql.entity.user.User;
import com.cakk.domain.mysql.entity.user.UserWithdrawal;
import com.cakk.domain.mysql.facade.user.UserCommandFacade;
import com.cakk.domain.mysql.repository.reader.UserReader;
import com.cakk.domain.mysql.repository.writer.BusinessInformationWriter;
import com.cakk.domain.mysql.repository.writer.CakeHeartWriter;
import com.cakk.domain.mysql.repository.writer.CakeShopHeartWriter;
import com.cakk.domain.mysql.repository.writer.UserWriter;

@Service
@RequiredArgsConstructor
public class UserService {

private final UserReader userReader;
private final UserWriter userWriter;
private final CakeShopHeartWriter cakeShopHeartWriter;
private final CakeHeartWriter cakeHeartWriter;
private final BusinessInformationWriter businessInformationWriter;
private final UserCommandFacade userCommandFacade;

@Transactional(readOnly = true)
public ProfileInformationResponse findProfile(final User signInUser) {
Expand All @@ -39,18 +33,14 @@ public void updateInformation(final User signInUser, final ProfileUpdateRequest
final User user = userReader.findByUserId(signInUser.getId());
final ProfileUpdateParam param = UserMapper.supplyProfileUpdateParamBy(dto);

user.updateProfile(param);
userCommandFacade.updateProfile(user, param);
}

@Transactional
public void withdraw(final User signInUser) {
final User user = userReader.findByUserId(signInUser.getId());
final User user = userReader.findByIdWithAll(signInUser.getId());
final UserWithdrawal withdrawal = UserMapper.supplyUserWithdrawalBy(user);

cakeHeartWriter.deleteAllByUser(user);
cakeShopHeartWriter.deleteAllByUser(user);
businessInformationWriter.deleteAllByUser(user);

userWriter.delete(user, withdrawal);
userCommandFacade.withdraw(user, withdrawal);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.cakk.api.common.base;

import java.time.LocalDate;

import org.junit.jupiter.api.extension.ExtendWith;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.GeometryFactory;
Expand All @@ -18,6 +20,7 @@
import com.navercorp.fixturemonkey.jakarta.validation.plugin.JakartaValidationPlugin;

import com.cakk.common.enums.Provider;
import com.cakk.common.enums.Role;
import com.cakk.domain.mysql.config.JpaConfig;
import com.cakk.domain.mysql.entity.user.User;

Expand Down Expand Up @@ -55,10 +58,14 @@ protected final FixtureMonkey getBuilderMonkey() {
}

protected User getUser() {
return getReflectionMonkey().giveMeBuilder(User.class)
return getConstructorMonkey().giveMeBuilder(User.class)
.set("id", Arbitraries.longs().greaterOrEqual(10))
.set("provider", Arbitraries.of(Provider.class))
.set("providerId", Arbitraries.strings().withCharRange('a', 'z').ofMinLength(1).ofMaxLength(50))
.set("email", Arbitraries.strings().withCharRange('a', 'z').ofMinLength(1).ofMaxLength(50))
.set("nickname", Arbitraries.strings().withCharRange('a', 'z').ofMinLength(1).ofMaxLength(50))
.set("birthday", LocalDate.now())
.set("role", Arbitraries.of(Role.class))
.sample();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.*;

import java.time.LocalDate;
import java.util.Map;

import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
Expand All @@ -28,11 +27,12 @@
import com.cakk.common.exception.CakkException;
import com.cakk.common.response.ApiResponse;
import com.cakk.domain.mysql.entity.user.User;
import com.cakk.domain.mysql.repository.reader.UserReader;

@SqlGroup({
@Sql(scripts = {
"/sql/insert-test-user.sql"
"/sql/insert-test-user.sql",
"/sql/insert-cake-shop.sql",
"/sql/insert-heart.sql",
}, executionPhase = BEFORE_TEST_METHOD),
@Sql(scripts = "/sql/delete-all.sql", executionPhase = AFTER_TEST_METHOD)
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
import com.cakk.common.enums.ReturnCode;
import com.cakk.common.exception.CakkException;
import com.cakk.domain.mysql.entity.user.User;
import com.cakk.domain.mysql.facade.user.UserCommandFacade;
import com.cakk.domain.mysql.repository.reader.UserReader;
import com.cakk.domain.mysql.repository.writer.UserWriter;
import com.cakk.domain.redis.repository.TokenRedisRepository;

@DisplayName("Sign 관련 비즈니스 로직 테스트")
Expand All @@ -42,7 +42,7 @@ class SignServiceTest extends ServiceTest {
private UserReader userReader;

@Mock
private UserWriter userWriter;
private UserCommandFacade userCommandFacade;

@Mock
private TokenRedisRepository tokenRedisRepository;
Expand All @@ -51,7 +51,7 @@ class SignServiceTest extends ServiceTest {
void signUp1() {
// given
UserSignUpRequest dto = getConstructorMonkey().giveMeOne(UserSignUpRequest.class);
User user = getReflectionMonkey().giveMeBuilder(User.class)
User user = getConstructorMonkey().giveMeBuilder(User.class)
.set("id", Arbitraries.longs().greaterOrEqual(10))
.set("provider", dto.provider())
.set("providerId", Arbitraries.strings().alpha().ofMinLength(10).ofMaxLength(20))
Expand All @@ -63,7 +63,7 @@ void signUp1() {
.sample();

doReturn(user.getProviderId()).when(oidcProviderFactory).getProviderId(dto.provider(), dto.idToken());
doReturn(user).when(userWriter).create(any(User.class));
doReturn(user).when(userCommandFacade).create(any(User.class));
doReturn(jwt).when(jwtProvider).generateToken(user);

// when
Expand All @@ -75,15 +75,15 @@ void signUp1() {
Assertions.assertNotNull(result.grantType());

verify(oidcProviderFactory, times(1)).getProviderId(dto.provider(), dto.idToken());
verify(userWriter, times(1)).create(any(User.class));
verify(userCommandFacade, times(1)).create(any(User.class));
verify(jwtProvider, times(1)).generateToken(user);
}

@TestWithDisplayName("만료된 id token이라면 회원가입 시 에러를 던진다")
void signUp2() {
// given
UserSignUpRequest dto = getConstructorMonkey().giveMeOne(UserSignUpRequest.class);
User user = getReflectionMonkey().giveMeBuilder(User.class)
User user = getConstructorMonkey().giveMeBuilder(User.class)
.set("id", Arbitraries.longs().greaterOrEqual(10))
.set("provider", dto.provider())
.set("providerId", Arbitraries.strings().alpha().ofMinLength(10).ofMaxLength(20))
Expand All @@ -98,7 +98,7 @@ void signUp2() {
ReturnCode.EXPIRED_JWT_TOKEN.getMessage());

verify(oidcProviderFactory, times(1)).getProviderId(dto.provider(), dto.idToken());
verify(userWriter, times(0)).create(any(User.class));
verify(userCommandFacade, times(0)).create(any(User.class));
verify(jwtProvider, times(0)).generateToken(user);
}

Expand All @@ -107,7 +107,7 @@ void signIn() {
// given
UserSignInRequest dto = getConstructorMonkey().giveMeOne(UserSignInRequest.class);
String providerId = Arbitraries.strings().alpha().ofMinLength(10).ofMaxLength(20).sample();
User user = getReflectionMonkey().giveMeBuilder(User.class)
User user = getConstructorMonkey().giveMeBuilder(User.class)
.set("id", Arbitraries.longs().greaterOrEqual(10))
.set("provider", dto.provider())
.set("providerId", providerId)
Expand Down Expand Up @@ -140,7 +140,7 @@ void signIn2() {
// given
UserSignInRequest dto = getConstructorMonkey().giveMeOne(UserSignInRequest.class);
String providerId = Arbitraries.strings().alpha().ofMinLength(10).ofMaxLength(20).sample();
User user = getReflectionMonkey().giveMeBuilder(User.class)
User user = getConstructorMonkey().giveMeBuilder(User.class)
.set("id", Arbitraries.longs().greaterOrEqual(10))
.set("provider", dto.provider())
.set("providerId", providerId)
Expand All @@ -164,7 +164,7 @@ void signIn2() {
void recreateToken() {
// given
final String refreshToken = "refresh token";
final User user = getReflectionMonkey().giveMeBuilder(User.class)
final User user = getConstructorMonkey().giveMeBuilder(User.class)
.set("id", Arbitraries.longs().greaterOrEqual(10))
.set("providerId", Arbitraries.strings().alpha().ofMinLength(10).ofMaxLength(20))
.set("createdAt", LocalDateTime.now())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,8 @@
import com.cakk.common.enums.ReturnCode;
import com.cakk.common.exception.CakkException;
import com.cakk.domain.mysql.entity.user.User;
import com.cakk.domain.mysql.facade.user.UserCommandFacade;
import com.cakk.domain.mysql.repository.reader.UserReader;
import com.cakk.domain.mysql.repository.writer.BusinessInformationWriter;
import com.cakk.domain.mysql.repository.writer.CakeHeartWriter;
import com.cakk.domain.mysql.repository.writer.CakeShopHeartWriter;
import com.cakk.domain.mysql.repository.writer.UserWriter;

@DisplayName("유저 관련 비즈니스 로직 테스트")
class UserServiceTest extends ServiceTest {
Expand All @@ -33,21 +30,12 @@ class UserServiceTest extends ServiceTest {
private UserReader userReader;

@Mock
private UserWriter userWriter;

@Mock
private CakeShopHeartWriter cakeShopHeartWriter;

@Mock
private CakeHeartWriter cakeHeartWriter;

@Mock
private BusinessInformationWriter businessInformationWriter;
private UserCommandFacade userCommandFacade;

@TestWithDisplayName("유저 프로필을 조회한다.")
void findProfile1() {
// given
final User user = getReflectionMonkey().giveMeBuilder(User.class)
final User user = getConstructorMonkey().giveMeBuilder(User.class)
.set("id", Arbitraries.longs().greaterOrEqual(10))
.set("provider", Arbitraries.of(Provider.class))
.set("providerId", Arbitraries.strings().withCharRange('a', 'z').ofMinLength(1).ofMaxLength(50))
Expand All @@ -67,7 +55,7 @@ void findProfile1() {
@TestWithDisplayName("유저가 존재하지 않으면 유저 프로필 조회에 실패한다.")
void findProfile2() {
// given
final User user = getReflectionMonkey().giveMeBuilder(User.class)
final User user = getConstructorMonkey().giveMeBuilder(User.class)
.set("id", Arbitraries.longs().greaterOrEqual(10))
.set("provider", Arbitraries.of(Provider.class))
.set("providerId", Arbitraries.strings().withCharRange('a', 'z').ofMinLength(1).ofMaxLength(50))
Expand All @@ -86,7 +74,7 @@ void findProfile2() {
@TestWithDisplayName("유저 프로필을 수정한다.")
void updateInformation() {
// given
final User user = getReflectionMonkey().giveMeBuilder(User.class)
final User user = getConstructorMonkey().giveMeBuilder(User.class)
.set("id", Arbitraries.longs().greaterOrEqual(10))
.set("provider", Arbitraries.of(Provider.class))
.set("providerId", Arbitraries.strings().withCharRange('a', 'z').ofMinLength(1).ofMaxLength(50))
Expand All @@ -104,44 +92,30 @@ void updateInformation() {
@TestWithDisplayName("유저를 탈퇴한다.")
void withdraw1() {
// given
final User user = getReflectionMonkey().giveMeBuilder(User.class)
.set("id", Arbitraries.longs().greaterOrEqual(10))
.set("provider", Arbitraries.of(Provider.class))
.set("providerId", Arbitraries.strings().withCharRange('a', 'z').ofMinLength(1).ofMaxLength(50))
.sample();
final User user = getUser();

doReturn(user).when(userReader).findByUserId(user.getId());
doReturn(user).when(userReader).findByIdWithAll(user.getId());

// when & then
Assertions.assertDoesNotThrow(() -> userService.withdraw(user));

verify(userReader, times(1)).findByUserId(user.getId());
verify(cakeHeartWriter, times(1)).deleteAllByUser(user);
verify(cakeShopHeartWriter, times(1)).deleteAllByUser(user);
verify(businessInformationWriter, times(1)).deleteAllByUser(user);
verify(userWriter, times(1)).delete(any(), any());
verify(userReader, times(1)).findByIdWithAll(user.getId());
verify(userCommandFacade, times(1)).withdraw(any(), any());
}

@TestWithDisplayName("유저가 없는 경우, 탈퇴에 실패한다.")
void withdraw2() {
// given
final User user = getReflectionMonkey().giveMeBuilder(User.class)
.set("id", Arbitraries.longs().greaterOrEqual(10))
.set("provider", Arbitraries.of(Provider.class))
.set("providerId", Arbitraries.strings().withCharRange('a', 'z').ofMinLength(1).ofMaxLength(50))
.sample();
final User user = getUser();

doThrow(new CakkException(ReturnCode.NOT_EXIST_USER)).when(userReader).findByUserId(user.getId());
doThrow(new CakkException(ReturnCode.NOT_EXIST_USER)).when(userReader).findByIdWithAll(user.getId());

// when & then
Assertions.assertThrows(CakkException.class,
() -> userService.withdraw(user),
ReturnCode.NOT_EXIST_USER.getMessage());

verify(userReader, times(1)).findByUserId(user.getId());
verify(cakeHeartWriter, times(0)).deleteAllByUser(user);
verify(cakeShopHeartWriter, times(0)).deleteAllByUser(user);
verify(businessInformationWriter, times(0)).deleteAllByUser(user);
verify(userWriter, times(0)).delete(any(), any());
verify(userReader, times(1)).findByIdWithAll(user.getId());
verify(userCommandFacade, never()).withdraw(any(), any());
}
}
2 changes: 2 additions & 0 deletions cakk-domain/mysql/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ dependencies {
testImplementation("com.navercorp.fixturemonkey:fixture-monkey-starter:1.0.23")
testImplementation('org.assertj:assertj-core')
testImplementation('org.junit.jupiter:junit-jupiter')
testImplementation('org.mockito:mockito-core')
testImplementation('org.mockito:mockito-junit-jupiter')
testRuntimeOnly('org.junit.platform:junit-platform-launcher')

// querydsl
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public class BusinessInformation extends AuditEntity {
@ColumnDefault("0")
@Convert(converter = VerificationStatusConverter.class)
@Column(name = "verification_status", nullable = false)
private VerificationStatus verificationStatus = VerificationStatus.UNREQUESTED;
private VerificationStatus verificationStatus;

@OneToOne
@MapsId
Expand Down Expand Up @@ -85,6 +85,11 @@ public void updateBusinessOwner(final VerificationPolicy verificationPolicy, fin
verificationStatus = verificationPolicy.approveToBusinessOwner(verificationStatus);
}

public void unLinkBusinessOwner() {
user = null;
verificationStatus = VerificationStatus.UNREQUESTED;
}

public boolean isBusinessOwnerCandidate(VerificationPolicy verificationPolicy) {
return verificationPolicy.isCandidate(Objects.requireNonNull(verificationStatus));
}
Expand Down
Loading
Loading