Skip to content

feature/#98 User 단위 및 통합 테스트코드 구현 #101

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

Merged
merged 12 commits into from
Nov 16, 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
14 changes: 0 additions & 14 deletions .coderabbit.yaml

This file was deleted.

10 changes: 9 additions & 1 deletion aics-api/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,20 @@ bootJar {
}

jar {
enabled = false
enabled = true
}

dependencies {
implementation project(':aics-domain')
implementation project(':aics-common')
implementation project(':aics-infra')
implementation project(':aics-global-utils')

testFixturesImplementation project(':aics-domain')
testFixturesImplementation project(':aics-common')
testFixturesImplementation project(':aics-infra')
testFixturesImplementation project(':aics-global-utils')

testFixturesImplementation testFixtures(project(':aics-domain'))
testFixturesImplementation testFixtures(project(':aics-global-utils'))
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
import kgu.developers.api.user.application.UserService;
import kgu.developers.common.auth.jwt.TokenProvider;
import kgu.developers.domain.user.domain.User;
import lombok.Builder;
import lombok.RequiredArgsConstructor;

@Service
@Builder
@RequiredArgsConstructor
public class AuthService {
private final UserService userService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
import kgu.developers.api.auth.application.AuthService;
import kgu.developers.api.auth.presentation.request.LoginRequest;
import kgu.developers.api.auth.presentation.response.TokenResponse;
import lombok.Builder;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Builder
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

@builder 어노테이션 제거 시 테스트 코드 수정 필요

TestContainer.java 파일에서 AuthController.builder()를 사용하고 있어 수정이 필요합니다:

  • aics-api/src/testFixtures/java/mock/TestContainer.java에서 AuthController 빌더 패턴 사용 중
🔗 Analysis chain

테스트 코드에 미치는 영향 확인 필요

@builder 어노테이션 제거가 테스트 코드에 영향을 미칠 수 있습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if any test files are using AuthController's builder pattern

# Search for AuthController.builder() usage in test files
rg -t java "AuthController\.builder\(\)" src/test/

Length of output: 102


Script:

#!/bin/bash
# First, let's find all test files in the repository
fd -t f "Test.*\.java$"

# Then, let's search for any builder pattern usage related to AuthController
rg -t java "AuthController.*builder" 

# Also check for any test files that might be importing or using AuthController
rg -t java "AuthController" 

Length of output: 1209

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/auth")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Builder;

@Builder
public record LoginRequest(
@Schema(description = "학번", example = "202412345", requiredMode = REQUIRED)
@NotNull
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@
import kgu.developers.domain.user.domain.User;
import kgu.developers.domain.user.domain.UserRepository;
import kgu.developers.domain.user.exception.UserNotFoundException;
import lombok.Builder;
import lombok.RequiredArgsConstructor;

@Service
@Builder
@RequiredArgsConstructor
public class UserService {
private final BCryptPasswordEncoder bCryptPasswordEncoder;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import kgu.developers.domain.user.domain.Major;
import lombok.Builder;

@Builder
public record UserCreateRequest(

@Schema(description = "학번", example = "202412345", requiredMode = REQUIRED)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Pattern;
import lombok.Builder;

@Builder
public record UserUpdateRequest(
@Schema(description = "전화번호", example = "010-1234-5678", requiredMode = REQUIRED)
@Pattern(regexp = "^\\d{2,4}-\\d{3,4}-\\d{4}$", message = "유효한 전화번호 형식이 아닙니다.")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package auth.application;

import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.AssertionsForClassTypes.assertThatCode;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import kgu.developers.api.auth.application.AuthService;
import kgu.developers.api.auth.presentation.exception.InvalidPasswordException;
import kgu.developers.api.auth.presentation.request.LoginRequest;
import kgu.developers.api.user.application.UserService;
import kgu.developers.common.auth.jwt.JwtProperties;
import kgu.developers.common.auth.jwt.TokenProvider;
import kgu.developers.domain.user.domain.Major;
import kgu.developers.domain.user.domain.User;
import mock.FakeUserRepository;

public class AuthServiceTest {
private AuthService authService;

@BeforeEach
public void init() {
FakeUserRepository fakeUserRepository = new FakeUserRepository();
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();

this.authService = AuthService.builder()
.userService(
UserService.builder()
.userRepository(fakeUserRepository)
.bCryptPasswordEncoder(bCryptPasswordEncoder)
.build()
)
.passwordEncoder(bCryptPasswordEncoder)
.tokenProvider(
TokenProvider.builder()
.jwtProperties(new JwtProperties("testIssuer", "testSecretKey"))
.build()
)
.build();

fakeUserRepository.save(User.builder()
.id("202411345")
.password(bCryptPasswordEncoder.encode("password1234"))
.name("홍길동")
.email("test@kyonggi.ac.kr")
.phone("010-1234-5678")
.major(Major.CSE)
.build());
}

@Test
@DisplayName("login은 토큰을 발급할 수 있다")
public void login_Success() {
// given
String userId = "202411345";
String password = "password1234";

// when
// then
assertThatCode(() -> {
authService.login(LoginRequest.builder()
.userId(userId)
.password(password)
.build()
);
}).doesNotThrowAnyException();
}

@Test
@DisplayName("login은 비밀번호가 틀리면 InvalidPasswordException을 발생시킨다")
public void login_InvalidPassword_ThrowsException() {
// given
String userId = "202411345";
String password = "wrongPassword";

// when
// then
assertThatThrownBy(() -> {
authService.login(LoginRequest.builder()
.userId(userId)
.password(password)
.build()
);
}).isInstanceOf(InvalidPasswordException.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package auth.presentation;

import static org.assertj.core.api.Assertions.assertThat;

import java.util.Objects;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseEntity;

import kgu.developers.api.auth.presentation.request.LoginRequest;
import kgu.developers.api.auth.presentation.response.TokenResponse;
import kgu.developers.api.user.presentation.request.UserCreateRequest;
import kgu.developers.domain.user.domain.Major;
import mock.TestContainer;
/*
* 추후 Controller 테스트는 medium test로 전환할 예정입니다.
* medium test는 Controller / Service / Repository 계층을 함께 테스트합니다.
*/
public class AuthControllerTest {

@Test
@DisplayName("로그인 성공 후 200 상태 코드와 토큰을 정상적으로 발급받는다")
public void login_Success() {
// given
TestContainer testContainer = new TestContainer();
testContainer.userService.createUser(UserCreateRequest.builder()
.userId("202411345")
.password("password0000")
.name("김철수")
.email("kim@kyonggi.ac.kr")
.phone("010-0000-0000")
.major(Major.CSE)
.build());

// when
ResponseEntity<TokenResponse> result = testContainer.authController.login(LoginRequest.builder()
.userId("202411345")
.password("password0000")
.build());

// then
assertThat(result.getStatusCode()).isEqualTo(HttpStatusCode.valueOf(200));
assertThat(Objects.requireNonNull(result.getBody()).accessToken()).isNotNull();
assertThat(Objects.requireNonNull(result.getBody()).refreshToken()).isNotNull();
}
}
37 changes: 37 additions & 0 deletions aics-api/src/testFixtures/java/mock/TestContainer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package mock;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import kgu.developers.api.auth.application.AuthService;
import kgu.developers.api.auth.presentation.AuthController;
import kgu.developers.api.user.application.UserService;
import kgu.developers.common.auth.jwt.JwtProperties;
import kgu.developers.common.auth.jwt.TokenProvider;
import kgu.developers.domain.user.domain.UserRepository;

public class TestContainer {
public final UserRepository userRepository;
public final UserService userService;
public final AuthService authService;
public final AuthController authController;

public TestContainer() {
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
this.userRepository = new FakeUserRepository();
this.userService = UserService.builder()
.userRepository(this.userRepository)
.bCryptPasswordEncoder(bCryptPasswordEncoder)
.build();
this.authService = AuthService.builder()
.userService(this.userService)
.passwordEncoder(bCryptPasswordEncoder)
.tokenProvider(TokenProvider.builder()
.jwtProperties(new JwtProperties("testIssuer", "testSecretKey"))
.build()
)
.build();
this.authController = AuthController.builder()
.authService(this.authService)
.build();
}
Comment on lines +18 to +36
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

테스트 성능 및 유지보수성 개선 제안

몇 가지 개선 사항을 제안드립니다:

  1. 테스트 성능 향상을 위한 BCryptPasswordEncoder 설정:
- BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
+ // 테스트 환경에서는 낮은 강도를 사용하여 성능 향상
+ BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder(4);
  1. 컴포넌트 초기화 모듈화:
+ private TokenProvider createTokenProvider() {
+     return TokenProvider.builder()
+         .jwtProperties(new JwtProperties("testIssuer", "testSecretKey"))
+         .build();
+ }
+
+ private UserService createUserService(BCryptPasswordEncoder encoder) {
+     return UserService.builder()
+         .userRepository(this.userRepository)
+         .bCryptPasswordEncoder(encoder)
+         .build();
+ }
  1. 테스트 설정값 상수화:
+ private static final String TEST_ISSUER = "testIssuer";
+ private static final String TEST_SECRET_KEY = "testSecretKey";

Committable suggestion skipped: line range outside the PR's diff.

}
Loading