Skip to content

Commit

Permalink
Merge pull request #93 from JNU-econovation/test/#92/login-test
Browse files Browse the repository at this point in the history
[Test] 로그인 business layer 테스트 코드
  • Loading branch information
kssumin authored Oct 11, 2023
2 parents 8dbec57 + cb66c06 commit 35909b7
Show file tree
Hide file tree
Showing 13 changed files with 356 additions and 30 deletions.
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
package com.econovation.overflow.auth.domain.helper;

import org.mindrot.jbcrypt.BCrypt;
import org.springframework.stereotype.Component;
public interface Encoder {
String encode(String raw);

@Component
public class Encoder {
public String encode(String raw) {
return BCrypt.hashpw(raw, BCrypt.gensalt());
}

public boolean matches(String raw, String hashed) {
return BCrypt.checkpw(raw, hashed);
}
boolean matches(String raw, String hashed);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.econovation.overflow.auth.domain.helper;

import org.mindrot.jbcrypt.BCrypt;
import org.springframework.stereotype.Component;

@Component
public class EncoderImpl implements Encoder {
public String encode(String raw) {
return BCrypt.hashpw(raw, BCrypt.gensalt());
}

public boolean matches(String raw, String hashed) {
return BCrypt.checkpw(raw, hashed);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.econovation.overflow.auth.domain.service;

import com.econovation.overflow.auth.domain.exception.AuthorizationException;
import com.econovation.overflow.auth.persistence.entity.AuthInfoEntity;
import com.econovation.overflow.auth.persistence.repository.AuthInfoRepository;
import com.econovation.overflow.support.token.TokenResolver;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class GetAuthInfoService {
private final TokenResolver tokenResolver;
private final AuthInfoRepository authInfoRepository;

public AuthInfoEntity execute(String token) {
Long userId = tokenResolver.getUserInfo(token);

return authInfoRepository
.findByUserIdAndToken(userId, token)
.orElseThrow(() -> new AuthorizationException("잘못된 토큰 입니다"));
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package com.econovation.overflow.auth.domain.usecase;

import com.econovation.overflow.auth.domain.dto.response.TokenResponse;
import com.econovation.overflow.auth.domain.exception.AuthorizationException;
import com.econovation.overflow.auth.domain.service.CreateTokenService;
import com.econovation.overflow.auth.domain.service.GetAuthInfoService;
import com.econovation.overflow.auth.persistence.entity.AuthInfoEntity;
import com.econovation.overflow.auth.persistence.repository.AuthInfoRepository;
import com.econovation.overflow.support.token.TokenResolver;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
Expand All @@ -16,20 +15,15 @@
@Transactional(readOnly = true)
@Slf4j
public class ReissueUseCase {
private final GetAuthInfoService getAuthInfoService;
private final CreateTokenService createTokenService;
private final TokenResolver tokenResolver;
private final AuthInfoRepository authInfoRepository;

@Transactional
public TokenResponse execute(final String token) {
Long userId = tokenResolver.getUserInfo(token);

AuthInfoEntity authInfoEntity =
authInfoRepository
.findByUserIdAndToken(userId, token)
.orElseThrow(() -> new AuthorizationException("잘못된 토큰 입니다"));

AuthInfoEntity authInfoEntity = getAuthInfoService.execute(token);
authInfoRepository.delete(authInfoEntity);
return createTokenService.execute(userId);

return createTokenService.execute(authInfoEntity.getUserId());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import javax.crypto.SecretKey;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class TokenResolver {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,38 @@
package com.econovation.overflow.auth.domain.model.converter;

import static org.mockito.Mockito.verify;

import com.econovation.overflow.auth.domain.dto.request.SaveUserRequest;
import com.econovation.overflow.auth.domain.helper.Encoder;
import com.econovation.overflow.auth.domain.model.UserModel;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.security.crypto.password.PasswordEncoder;

@ExtendWith(MockitoExtension.class)
class UserModelConverterTest {

@Mock private PasswordEncoder passwordEncoder;
@Mock private Encoder encoder;
@InjectMocks private UserModelConverter userModelConverter;
private static final String PASSWORD = "password";

@Test
@DisplayName("request를 model로 변환한다.")
void request_convert_model() {
// given
SaveUserRequest request = SaveUserRequest.builder().build();

// when
UserModel model = userModelConverter.from(request);

// then
Assertions.assertThat(model).isInstanceOf(UserModel.class);
}

@Test
@DisplayName("request를 model로 변환할 때 암호화를 진행한다.")
void encode_convert_model() {
Expand All @@ -28,6 +43,6 @@ void encode_convert_model() {
UserModel model = userModelConverter.from(request);

// then
Mockito.verify(passwordEncoder).encode(PASSWORD);
verify(encoder).encode(PASSWORD);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.econovation.overflow.auth.domain.service;

import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import com.econovation.overflow.auth.domain.dto.converter.TokenConverter;
import com.econovation.overflow.auth.domain.dto.response.TokenResponse;
import com.econovation.overflow.auth.persistence.converter.AuthInfoEntityConverter;
import com.econovation.overflow.auth.persistence.entity.AuthInfoEntity;
import com.econovation.overflow.auth.persistence.repository.AuthInfoRepository;
import com.econovation.overflow.support.token.TokenProvider;
import com.econovation.overflow.support.token.TokenResolver;
import java.time.Instant;
import java.util.Date;
import org.junit.jupiter.api.DisplayName;
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;

@ExtendWith(MockitoExtension.class)
class CreateTokenServiceTest {
@Mock private TokenProvider tokenProvider;
@Mock private TokenResolver tokenResolver;
@Mock private TokenConverter tokenConverter;
@Mock private AuthInfoRepository authInfoRepository;
@Mock private AuthInfoEntityConverter authInfoEntityConverter;
@InjectMocks private CreateTokenService createTokenService;

@Test
@DisplayName("토큰을 저장 메시지를 전달한다.")
void save_token() {
// given
Long userId = 1L;
Date expiredDate = Date.from(Instant.EPOCH);

String accessToken = tokenProvider.createAccessToken(userId);
String refreshToken = tokenProvider.createRefreshToken(userId);
TokenResponse tokenResponse = TokenResponse.builder().build();

AuthInfoEntity authInfoEntity = authInfoEntityConverter.from(userId, refreshToken);
when(tokenResolver.getExpiredDate(accessToken)).thenReturn(expiredDate);
when(tokenConverter.from(accessToken, expiredDate, refreshToken)).thenReturn(tokenResponse);

// when
createTokenService.execute(userId);

// then
verify(authInfoRepository).save(authInfoEntity);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.econovation.overflow.auth.domain.service;

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

import com.econovation.overflow.auth.domain.exception.AuthorizationException;
import com.econovation.overflow.auth.persistence.entity.AuthInfoEntity;
import com.econovation.overflow.auth.persistence.repository.AuthInfoRepository;
import com.econovation.overflow.support.token.TokenResolver;
import java.util.Optional;
import org.junit.jupiter.api.DisplayName;
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;

@ExtendWith(MockitoExtension.class)
class GetAuthInfoServiceTest {
@Mock private TokenResolver tokenResolver;

@Mock private AuthInfoRepository authInfoRepository;

@InjectMocks private GetAuthInfoService getAuthInfoService;

@Test
@DisplayName("token으로부터 auth 정보를 가져온다.")
void get_auth_info_by_token() {
// given
Long userId = 1L;
String token = "token";

AuthInfoEntity actual = AuthInfoEntity.builder().build();
when(tokenResolver.getUserInfo(token)).thenReturn(userId);
when(authInfoRepository.findByUserIdAndToken(userId, token))
.thenReturn(Optional.ofNullable(actual));

// then
AuthInfoEntity expected = getAuthInfoService.execute(token);

// then
assertEquals(expected, actual);
}

@Test
@DisplayName("token과 유저 정보에 해당하는 auth정보가 없다면 예외가 발생한다.")
void exception_when_get_auth_info_by_token() {
// given
Long userId = 1L;
String token = "token";

when(tokenResolver.getUserInfo(token)).thenReturn(userId);
when(authInfoRepository.findByUserIdAndToken(userId, token))
.thenThrow(AuthorizationException.class);

// then & then
assertThrows(AuthorizationException.class, () -> getAuthInfoService.execute(token));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.econovation.overflow.auth.domain.service;

import static org.mockito.Mockito.*;

import com.econovation.overflow.auth.persistence.converter.AuthInfoEntityConverter;
import com.econovation.overflow.auth.persistence.entity.AuthInfoEntity;
import com.econovation.overflow.auth.persistence.repository.AuthInfoRepository;
import org.junit.jupiter.api.DisplayName;
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;

@ExtendWith(MockitoExtension.class)
class SaveTokenServiceTest {
@Mock private AuthInfoRepository authInfoRepository;

@InjectMocks private SaveTokenService saveTokenService;

@Mock private AuthInfoEntityConverter converter;

@Test
@DisplayName("유저 id, 토큰 정보를 가진 entity를 authInfoRepository에게 save메시지를 전달한다.")
void execute() {
// given
Long userId = 1L;
String token = "token";

AuthInfoEntity entity = AuthInfoEntity.builder().userId(userId).token(token).build();
when(converter.from(userId, token)).thenReturn(entity);

// when
saveTokenService.execute(userId, token);

// then
verify(authInfoRepository).save(entity);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.econovation.overflow.auth.domain.usecase;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;

import com.econovation.overflow.auth.domain.dto.request.LoginUserRequest;
import com.econovation.overflow.auth.domain.dto.response.TokenResponse;
import com.econovation.overflow.auth.domain.exception.NotFoundEmailException;
import com.econovation.overflow.auth.domain.exception.NotFoundPasswordException;
import com.econovation.overflow.auth.domain.helper.Encoder;
import com.econovation.overflow.auth.domain.service.CreateTokenService;
import com.econovation.overflow.auth.persistence.entity.UserEntity;
import com.econovation.overflow.auth.persistence.repository.UserRepository;
import java.util.Optional;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
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;

@ExtendWith(MockitoExtension.class)
class LoginUserUseCaseTest {
@Mock private UserRepository userRepository;

@Mock private CreateTokenService createTokenService;

@InjectMocks private LoginUserUseCase loginUserUseCase;

@Mock private Encoder encoder;

@Test
@DisplayName("로그인 시 존재하지 않는 이메일이면 예외가 발생한다.")
void exist_email_check_when_login() {
// given
LoginUserRequest request = LoginUserRequest.builder().build();
when(userRepository.findByEmail(any())).thenReturn(Optional.empty());

// when & then
assertThrows(NotFoundEmailException.class, () -> loginUserUseCase.execute(request));
}

@Test
@DisplayName("로그인 시 비밀번호가 맞지 않으면 예외가 발생한다.")
void same_password_check_when_login() {
// given
LoginUserRequest request = LoginUserRequest.builder().build();
UserEntity entity = UserEntity.builder().build();
when(userRepository.findByEmail(any())).thenReturn(Optional.of(entity));
when(encoder.matches(any(), any())).thenReturn(Boolean.FALSE);

// when & then
assertThrows(NotFoundPasswordException.class, () -> loginUserUseCase.execute(request));
}

@Test
@DisplayName("로그인을 성공하면 토큰 정보를 전달한다.")
void pass_token_info_when_success_login() {
// given
LoginUserRequest request = LoginUserRequest.builder().email(any()).build();
UserEntity entity = UserEntity.builder().build();
TokenResponse expected = TokenResponse.builder().build();

when(userRepository.findByEmail(request.getEmail())).thenReturn(Optional.of(entity));
when(encoder.matches(any(), any())).thenReturn(Boolean.TRUE);
when(createTokenService.execute(any())).thenReturn(expected);

// when
TokenResponse actual = loginUserUseCase.execute(request);

// then
Assertions.assertEquals(expected, actual);
}
}
Loading

0 comments on commit 35909b7

Please sign in to comment.