Skip to content

Commit

Permalink
test: Follow, FollowCommandService 팔로우 단위 테스트 작성
Browse files Browse the repository at this point in the history
  • Loading branch information
kwj1270 committed Nov 25, 2021
1 parent e52491e commit 5df1d0d
Show file tree
Hide file tree
Showing 14 changed files with 223 additions and 27 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.study.realworld.domain.follow.api;

import com.study.realworld.domain.follow.error.FollowErrorCode;
import com.study.realworld.domain.follow.error.FollowErrorResponse;
import com.study.realworld.domain.follow.error.exception.FollowBusinessException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;


@RestControllerAdvice
public class FollowApiAdvice {

private final Logger log = LogManager.getLogger(getClass());

@ExceptionHandler(FollowBusinessException.class)
protected ResponseEntity<FollowErrorResponse> handleUserBusinessException(final FollowBusinessException followBusinessException) {

log.error("FollowBusinessException: {}", followBusinessException.getMessage());

final FollowErrorCode followErrorCode = FollowErrorCode.values(followBusinessException);
final FollowErrorResponse followErrorResponse = FollowErrorResponse.from(followErrorCode);
return followErrorResponse.toResponseEntity();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.study.realworld.domain.follow.domain.FollowRepository;
import com.study.realworld.domain.follow.dto.FollowResponse;
import com.study.realworld.domain.follow.dto.UnFollowResponse;
import com.study.realworld.domain.follow.error.exception.DuplicatedFollowException;
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.UserName;
Expand All @@ -23,24 +24,25 @@ public class FollowCommandService {
public FollowResponse follow(final Long userId, final UserName userName) {
final User followee = userQueryService.findByUserName(userName);
final User follower = userQueryService.findById(userId);
if (followQueryService.existsByFolloweeAndFollower(followee, follower)) {
return FollowResponse.from(followee);
}
validateDuplicatedFollow(followee, follower);
final Follow follow = followBuilder(followee, follower);
return FollowResponse.from(followRepository.save(follow).followee());
}

public UnFollowResponse unfollow(final Long suerId, final UserName userName) {
final User followee = userQueryService.findByUserName(userName);
final User follower = userQueryService.findById(suerId);
if (!followQueryService.existsByFolloweeAndFollower(followee, follower)) {
return UnFollowResponse.from(followee);
}
final Follow follow = followQueryService.findByFolloweeAndFollower(followee, follower);
followRepository.delete(follow);
return UnFollowResponse.from(followee);
}

private void validateDuplicatedFollow(final User followee, final User follower) {
if (followQueryService.existsByFolloweeAndFollower(followee, follower)) {
throw new DuplicatedFollowException();
}
}

private Follow followBuilder(final User followee, final User follower) {
return Follow.builder()
.followee(followee)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.study.realworld.domain.follow.domain.FollowQueryDSLRepository;
import com.study.realworld.domain.follow.domain.FollowRepository;
import com.study.realworld.domain.follow.dto.ProfileResponse;
import com.study.realworld.domain.follow.error.exception.FollowNotFoundException;
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.UserName;
Expand All @@ -21,20 +22,20 @@ public class FollowQueryService {
private final FollowRepository followRepository;

public ProfileResponse profile(final Long userId, final UserName username) {
final User user = userQueryService.findById(userId);
final User me = userQueryService.findById(userId);
final User target = userQueryService.findByUserName(username);
final boolean isFollow = existsByFolloweeAndFollower(user, target);
final boolean isFollow = existsByFolloweeAndFollower(target, me);
return new ProfileResponse(target, isFollow);
}

public boolean existsByFolloweeAndFollower(final User user, final User target) {
return followRepository.existsByFolloweeAndFollower(target, user);
public boolean existsByFolloweeAndFollower(final User followee, final User follower) {
return followRepository.existsByFolloweeAndFollower(followee, follower);
}

public Follow findByFolloweeAndFollower(final User followee, final User follower) {
return followRepository
.findByFolloweeAndFollower(followee, follower)
.orElseThrow(IllegalArgumentException::new);
.orElseThrow(FollowNotFoundException::new);
}

public ProfileResponse profile2(final Long userId, final UserName username) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.study.realworld.domain.follow.error;

import com.study.realworld.domain.follow.error.exception.DuplicatedFollowException;
import com.study.realworld.domain.follow.error.exception.FollowBusinessException;
import com.study.realworld.domain.follow.error.exception.FollowNotFoundException;
import com.study.realworld.global.error.ErrorCode;
import org.springframework.http.HttpStatus;

import java.util.Arrays;

public enum FollowErrorCode implements ErrorCode {

FOLLOW_NOT_FOUND(FollowNotFoundException.class, HttpStatus.BAD_REQUEST, "Follow is not exist"),
DUPLICATED_FOLLOW(DuplicatedFollowException.class, HttpStatus.BAD_REQUEST, "Follow is already exist");

private final Class exceptionClass;
private final HttpStatus httpStatus;
private final String message;

FollowErrorCode(final Class<?> exceptionClass, final HttpStatus httpStatus, final String message) {
this.exceptionClass = exceptionClass;
this.httpStatus = httpStatus;
this.message = message;
}

public static FollowErrorCode values(final FollowBusinessException exception) {
final Class<? extends FollowBusinessException> exceptionClass = exception.getClass();
return Arrays.stream(values())
.filter(userErrorCode -> userErrorCode.exceptionClass.equals(exceptionClass))
.findFirst()
.orElseThrow(IllegalArgumentException::new);
}

@Override
public HttpStatus httpStatus() {
return httpStatus;
}

@Override
public String message() {
return message;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.study.realworld.domain.follow.error;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeName;
import com.study.realworld.global.error.ErrorCode;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

import java.util.List;

@AllArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor(access = AccessLevel.PACKAGE)
@JsonTypeName("errors")
@JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT, use = JsonTypeInfo.Id.NAME)
public class FollowErrorResponse {

@JsonIgnore
private HttpStatus httpStatus;

@JsonProperty("body")
private List<String> body;

public static FollowErrorResponse from(final ErrorCode errorCode) {
return new FollowErrorResponse(errorCode.httpStatus(), List.of(errorCode.message()));
}

public ResponseEntity<FollowErrorResponse> toResponseEntity() {
return ResponseEntity.status(this.httpStatus).body(this);
}

public List<String> body() {
return body;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.study.realworld.domain.follow.error.exception;

public class DuplicatedFollowException extends FollowBusinessException {

private static final String DUPLICATED_FOLLOW_MESSAGE = "팔로우 정보가 이미 있습니다";

public DuplicatedFollowException() {
super(DUPLICATED_FOLLOW_MESSAGE);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.study.realworld.domain.follow.error.exception;

public class FollowBusinessException extends RuntimeException {

public FollowBusinessException(final String message) {
super(message);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.study.realworld.domain.follow.error.exception;

public class FollowNotFoundException extends FollowBusinessException {

private static final String FOLLOW_NOT_FOUND_MESSAGE = "팔로우 정보를 찾을 수 없습니다";

public FollowNotFoundException() {
super(FOLLOW_NOT_FOUND_MESSAGE);
}
}
6 changes: 5 additions & 1 deletion src/main/java/com/study/realworld/http/login.http
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
### JOIN
### JOIN, 삭제한 데이터에 대해서 배치나 스케줄링 써서 삭제하는 작업해야겠다.
POST localhost:8080/api/users
Content-Type: application/json

Expand Down Expand Up @@ -38,3 +38,7 @@ Authorization: {{Authorization}}
"image": "https://i.stack.imgur.com/xHWG8.jpg"
}
}

### DELETE
DELETE localhost:8080/api/users
Authorization: {{Authorization}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.study.realworld.domain.follow.application;

import com.study.realworld.domain.follow.domain.Follow;
import com.study.realworld.domain.follow.domain.FollowRepository;
import com.study.realworld.domain.follow.dto.FollowResponse;
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.UserBio;
import com.study.realworld.domain.user.domain.vo.UserImage;
import com.study.realworld.domain.user.domain.vo.UserName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import static com.study.realworld.domain.follow.domain.FollowTest.testFollower;
import static com.study.realworld.domain.user.domain.persist.UserTest.testUser;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.willReturn;

@ExtendWith(MockitoExtension.class)
class FollowCommandServiceTest {

@Mock
private UserQueryService userQueryService;

@Mock
private FollowQueryService followQueryService;

@Mock
private FollowRepository followRepository;

@InjectMocks
private FollowCommandService followCommandService;

@Test
void 팔로워_아이덴티티와_팔로위_이름을_입력하면_팔로우_할_수_있다() {
final User follower = testUser("user1@gmail.com", "user1", "password1", "bio1", "image1");
final User followee = testUser("user2@gmail.com", "user2", "password2", "bio2", "image2");
final Follow follow = testFollower(followee, follower);
willReturn(follower).given(userQueryService).findById(any());
willReturn(followee).given(userQueryService).findByUserName(any());
willReturn(false).given(followQueryService).existsByFolloweeAndFollower(any(), any());
willReturn(follow).given(followRepository).save(any());

final FollowResponse followResponse = followCommandService.follow(1L, UserName.from("user2"));
assertAll(
() -> assertThat(followResponse.userName()).isEqualTo(UserName.from("user2")),
() -> assertThat(followResponse.userBio()).isEqualTo(UserBio.from("bio2")),
() -> assertThat(followResponse.userImage()).isEqualTo(UserImage.from("image2")),
() -> assertThat(followResponse.isFollowing()).isTrue()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.study.realworld.domain.follow.application;

import static org.junit.jupiter.api.Assertions.*;

class FollowQueryServiceTest {

}
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("팔로우 (Follow)")
class FollowTest {
public class FollowTest {

@Test
void 두명의_유저들을_토대로_객체를_생성할_수_있다() {
Expand Down

This file was deleted.

This file was deleted.

0 comments on commit 5df1d0d

Please sign in to comment.