Skip to content

Commit

Permalink
[#54] refactor: UserCommandService 단위 테스트 작성
Browse files Browse the repository at this point in the history
  • Loading branch information
kwj1270 committed Nov 19, 2021
1 parent da1c809 commit db677e4
Show file tree
Hide file tree
Showing 14 changed files with 146 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class AuthApi {
public ResponseEntity<Login.Response> login(@Valid @RequestBody final Login.Request request) {
final User user = authService.login(request.userEmail(), request.userPassword());
final TokenProviderDto tokenProviderDto = TokenProviderDto.from(user);
final AccessToken accessToken = tokenProvider.createToken(tokenProviderDto);
final AccessToken accessToken = tokenProvider.createAccessToken(tokenProviderDto);
final Login.Response response = Login.Response.fromUserWithToken(user, accessToken);
return ResponseEntity.ok().body(response);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.study.realworld.domain.user.api;

import com.study.realworld.domain.user.domain.vo.UserEmail;
import com.study.realworld.global.common.TokenProviderDto;
import com.study.realworld.global.common.AccessToken;
import com.study.realworld.domain.user.application.UserCommandService;
Expand Down Expand Up @@ -28,17 +29,17 @@ public class UserCommandApi {
public ResponseEntity<UserJoin.Response> join(@Valid @RequestBody final UserJoin.Request request) {
final User user = userCommandService.join(request.toEntity());
final TokenProviderDto tokenProviderDto = TokenProviderDto.from(user);
final AccessToken accessToken = tokenProvider.createToken(tokenProviderDto);
final AccessToken accessToken = tokenProvider.createAccessToken(tokenProviderDto);
final UserJoin.Response response = UserJoin.Response.fromUserWithToken(user, accessToken);
return ResponseEntity.ok().body(response);
}

@PutMapping("/users")
public ResponseEntity<UserUpdate.Response> update(@AuthenticationPrincipal final Long principal,
public ResponseEntity<UserUpdate.Response> update(@Valid @AuthenticationPrincipal final Long userId,
@Valid @RequestBody final UserUpdate.Request request) {
final User user = userCommandService.update(principal, request);
final User user = userCommandService.update(userId, request);
final TokenProviderDto tokenProviderDto = TokenProviderDto.from(user);
final AccessToken accessToken = tokenProvider.createToken(tokenProviderDto);
final AccessToken accessToken = tokenProvider.createAccessToken(tokenProviderDto);
final UserUpdate.Response response = UserUpdate.Response.fromUserWithToken(user, accessToken);
return ResponseEntity.ok().body(response);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,18 @@ public User join(final User user) {
return userRepository.save(user);
}

public User update(final Long principal, final UserUpdate.Request request) {
public User update(final Long userId, final UserUpdate.Request request) {
validateDuplicatedEmail(request.memberEmail());
final User user = findUserByEmail(principal);
final User user = findUserById(userId);
return user.changeEmail(request.memberEmail())
.changeBio(request.memberBio())
.changeImage(request.memberImage());
}

private User findUserByEmail(final Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new IdentityNotFoundException(id));
private User findUserById(final Long userId) {
return userRepository
.findById(userId)
.orElseThrow(() -> new IdentityNotFoundException(userId));
}

private void validateDuplicatedEmail(final UserEmail userEmail) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class User extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id", nullable = false, updatable = false)
private Long id;
private Long userId;

@Embedded
private UserEmail userEmail;
Expand Down Expand Up @@ -68,6 +68,10 @@ public User changeImage(final UserImage userImage) {
return this;
}

public Long userId() {
return userId;
}

public UserEmail userEmail() {
return userEmail;
}
Expand All @@ -93,11 +97,11 @@ public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final User user = (User) o;
return Objects.equals(id, user.id);
return Objects.equals(userId(), user.userId());
}

@Override
public int hashCode() {
return Objects.hash(id);
return Objects.hash(userId());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UserBio userBio1 = (UserBio) o;
return Objects.equals(userBio, userBio1.userBio);
return Objects.equals(value(), userBio1.value());
}

@Override
public int hashCode() {
return Objects.hash(userBio);
return Objects.hash(value());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeName;
import com.study.realworld.global.common.AccessToken;
import com.study.realworld.domain.user.domain.persist.User;
import com.study.realworld.domain.user.domain.vo.UserBio;
import com.study.realworld.domain.user.domain.vo.UserEmail;
import com.study.realworld.domain.user.domain.vo.UserImage;
import com.study.realworld.domain.user.domain.vo.UserName;
import com.study.realworld.global.common.AccessToken;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;

public final class UserUpdate {

@AllArgsConstructor(access = AccessLevel.PACKAGE)
@NoArgsConstructor(access = AccessLevel.PACKAGE)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@JsonTypeName("user")
@JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT, use = JsonTypeInfo.Id.NAME)
public static final class Request {
Expand All @@ -41,10 +41,14 @@ public final UserBio memberBio() {
public final UserImage memberImage() {
return userImage;
}

public static final Request of(final UserEmail userEmail, final UserBio userBio, final UserImage userImage) {
return new Request(userEmail, userBio, userImage);
}
}

@AllArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor(access = AccessLevel.PACKAGE)
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@JsonTypeName("user")
@JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT, use = JsonTypeInfo.Id.NAME)
public static final class Response {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ public class IdentityNotFoundException extends UserBusinessException {

private static final String MESSAGE = "식별자 : [ %s ] 를 찾을 수 없습니다.";

public IdentityNotFoundException(final Long id) {
super(String.format(MESSAGE, id));
public IdentityNotFoundException(final Long identity) {
super(String.format(MESSAGE, identity));
}

}
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
package com.study.realworld.global.common;

import com.study.realworld.global.common.TokenProviderDto;
import com.study.realworld.global.common.AccessToken;
import com.study.realworld.domain.user.domain.vo.UserEmail;
import com.study.realworld.global.jwt.JwtAuthentication;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.io.Decoders;
Expand Down Expand Up @@ -30,9 +27,9 @@ public TokenProvider(@Value("${jwt.secret}") final String secretKey) {
this.key = Keys.hmacShaKeyFor(keyBytes);
}

public AccessToken createToken(final TokenProviderDto tokenProviderDto) {
public AccessToken createAccessToken(final TokenProviderDto tokenProviderDto) {
return new AccessToken(Jwts.builder()
.setSubject(tokenProviderDto.userEmail().value())
.setSubject(tokenProviderDto.userId().toString())
.setExpiration(expiration())
.signWith(key, HS512)
.compact());
Expand Down Expand Up @@ -62,9 +59,8 @@ private Optional<String> subject(final String token) {
}
}

public Authentication getAuthentication(final String jwt) {
final String email = subject(jwt).orElseThrow(IllegalArgumentException::new);
final UserEmail userEmail = UserEmail.from(email);
return JwtAuthentication.from(userEmail);
public Authentication getAuthentication(final String token) {
final String userId = subject(token).orElseThrow(IllegalArgumentException::new);
return JwtAuthentication.from(Long.valueOf(userId));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@

public class TokenProviderDto {

private Long userId;
private UserEmail userEmail;
private UserName userName;
private UserPassword userPassword;
private UserBio userBio;
private UserImage userImage;

@Builder
public TokenProviderDto(final UserEmail userEmail, final UserName userName,
public TokenProviderDto(final Long userId, final UserEmail userEmail, final UserName userName,
final UserPassword userPassword, final UserBio userBio, final UserImage userImage) {
this.userId = userId;
this.userEmail = userEmail;
this.userName = userName;
this.userPassword = userPassword;
Expand All @@ -24,6 +26,7 @@ public TokenProviderDto(final UserEmail userEmail, final UserName userName,

public static TokenProviderDto from(final User user) {
return TokenProviderDto.builder()
.userId(user.userId())
.userEmail(user.userEmail())
.userName(user.userName())
.userPassword(user.userPassword())
Expand All @@ -32,6 +35,10 @@ public static TokenProviderDto from(final User user) {
.build();
}

public Long userId() {
return userId;
}

public UserEmail userEmail() {
return userEmail;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public class JwtAuthentication extends AbstractAuthenticationToken {

private JwtAuthentication(final Object principal) {
super(null);
super.setAuthenticated(true);
this.principal = principal;
}

Expand Down
8 changes: 4 additions & 4 deletions src/main/java/com/study/realworld/http/login.http
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ Content-Type: application/json
%}

### UPDATE
PUT localhost:8080/api/members
PUT localhost:8080/api/users
Content-Type: application/json
Authorization: {{Authorization}}

{
"user":{
"userEmail": "jake@jake2.jake",
"userBio": "I like to skateboard",
"userImage": "https://i.stack.imgur.com/xHWG8.jpg"
"email": "jake@jake2.jake",
"bio": "I like to skateboard",
"image": "https://i.stack.imgur.com/xHWG8.jpg"
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package com.study.realworld.domain.user.application;

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.util.TestPasswordEncoder;
import com.study.realworld.domain.user.dto.UserUpdate;
import com.study.realworld.domain.user.error.exception.DuplicatedEmailException;
import com.study.realworld.domain.user.error.exception.IdentityNotFoundException;
import org.junit.jupiter.api.BeforeEach;
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.test.util.ReflectionTestUtils;

import java.util.Optional;

import static com.study.realworld.domain.user.domain.persist.UserTest.testUser;
import static com.study.realworld.domain.user.domain.vo.util.UserVOFixture.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.willReturn;

@ExtendWith(MockitoExtension.class)
class UserCommandServiceTest {

@Mock
private UserRepository userRepository;

private UserCommandService userCommandService;

@BeforeEach
void setUp() {
userCommandService = new UserCommandService(userRepository, TestPasswordEncoder.initialize());
}

@Test
void 이미_존재하는_엔티티가_없다면_회원가입에_성공한다() {
final User user = testUser(USER_EMAIL, USER_NAME, USER_PASSWORD, USER_BIO, USER_IMAGE);
ReflectionTestUtils.setField(user, "userId", 1L);
willReturn(false).given(userRepository).existsByUserEmail(any());
willReturn(user).given(userRepository).save(any());

final User joinedUser = userCommandService.join(user);
assertThat(joinedUser).isEqualTo(user);
}

@Test
void 이미_존재하는_엔티티가_있다면_회원가입에_싪패한다() {
final User user = testUser(USER_EMAIL, USER_NAME, USER_PASSWORD, USER_BIO, USER_IMAGE);
ReflectionTestUtils.setField(user, "userId", 1L);
willReturn(true).given(userRepository).existsByUserEmail(any());

assertThatThrownBy(() -> userCommandService.join(user))
.isExactlyInstanceOf(DuplicatedEmailException.class)
.hasMessage(String.format("이메일 : [ %s ] 가 이미 존재합니다.", user.userEmail().value()));
}

@Test
void 식별자가_올바르다면_엔티티의_값을_변경할_수_있다() {
final User user = testUser(USER_EMAIL, USER_NAME, USER_PASSWORD, USER_BIO, USER_IMAGE);
ReflectionTestUtils.setField(user, "userId", 1L);
willReturn(Optional.of(user)).given(userRepository).findById(any());

final UserUpdate.Request request = UserUpdate.Request.of(CHANGED_USER_EMAIL, CHANGED_USER_BIO, CHANGED_USER_IMAGE);
final User updatedUser = userCommandService.update(user.userId(), request);

assertAll(
() -> assertThat(updatedUser.userEmail()).isEqualTo(CHANGED_USER_EMAIL),
() -> assertThat(updatedUser.userBio()).isEqualTo(CHANGED_USER_BIO),
() -> assertThat(updatedUser.userImage()).isEqualTo(CHANGED_USER_IMAGE)
);
}

@Test
void 식별자가_올바르지_않다면_엔티티의_값을_변경할_수_없다() {
final User user = testUser(USER_EMAIL, USER_NAME, USER_PASSWORD, USER_BIO, USER_IMAGE);
ReflectionTestUtils.setField(user, "userId", 1L);
willReturn(Optional.empty()).given(userRepository).findById(any());

final UserUpdate.Request request = UserUpdate.Request.of(CHANGED_USER_EMAIL, CHANGED_USER_BIO, CHANGED_USER_IMAGE);
assertThatThrownBy(() -> userCommandService.update(2L, request))
.isExactlyInstanceOf(IdentityNotFoundException.class)
.hasMessage(String.format("식별자 : [ %s ] 를 찾을 수 없습니다.", 2L));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import static org.junit.jupiter.api.Assertions.assertAll;

@DisplayName("사용자(User)")
class UserTest {
public class UserTest {

@Test
void 빌더를_통해_객체를_생성할_수_있다() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,11 @@ public class UserVOFixture {
public static final UserPassword USER_PASSWORD = UserPassword.encode("userPassword", TestPasswordEncoder.initialize());
public static final UserBio USER_BIO = UserBio.from("userBio");
public static final UserImage USER_IMAGE = UserImage.from("userImage");

public static final UserEmail CHANGED_USER_EMAIL = UserEmail.from("changeEmail@email.com");
public static final UserName CHANGED_USER_NAME = UserName.from("changeUserName");
public static final UserPassword CHANGED_USER_PASSWORD = UserPassword.encode("changedUserPassword", TestPasswordEncoder.initialize());
public static final UserBio CHANGED_USER_BIO = UserBio.from("changedUserBio");
public static final UserImage CHANGED_USER_IMAGE = UserImage.from("changedUserImage");

}

0 comments on commit db677e4

Please sign in to comment.