Skip to content
Open
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
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,15 @@ dependencies {
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-validation', version: '2.7.5'
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-security', version: '2.7.5'
implementation group: 'io.springfox', name: 'springfox-boot-starter', version: '3.0.0'
testImplementation 'junit:junit:4.13.1'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.h2database:h2'
runtimeOnly 'org.postgresql:postgresql'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.8.0'


}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.techeer.cokkiri.domain.user.controller;

import static com.techeer.cokkiri.global.result.ResultCode.USER_LOGIN_SUCCESS;
import static com.techeer.cokkiri.global.result.ResultCode.USER_REGISTRATION_SUCCESS;
import static com.techeer.cokkiri.global.result.ResultCode.USER_USERNAME_NOT_DUPLICATED;
import static com.techeer.cokkiri.global.result.ResultCode.*;

import com.techeer.cokkiri.domain.user.dto.UserDto;
import com.techeer.cokkiri.domain.user.entity.User;
Expand Down Expand Up @@ -53,10 +51,10 @@ public ResponseEntity<ResultResponse> isDuplicatedUsername(@PathVariable String
@PostMapping("/login")
public ResponseEntity<ResultResponse> login(
@RequestBody @Valid UserDto.LoginRequest userRequest) {
boolean isValidUser = loginService.isValidUser(userRequest);
boolean isValid = loginService.isValidPassword(userRequest);

if (isValidUser) {
User user = userService.findUserByUsername(userRequest.getUsername());
if (isValid) {
User user = userService.findByUsername(userRequest.getUsername());
loginService.login(user.getId());
}
return ResponseEntity.ok(ResultResponse.of(USER_LOGIN_SUCCESS));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.techeer.cokkiri.domain.user.exception;

import com.techeer.cokkiri.global.error.ErrorCode;
import com.techeer.cokkiri.global.error.exception.BusinessException;

public class UserPasswordWrongException extends BusinessException {
public UserPasswordWrongException() {
super(ErrorCode.USER_PASSWORD_NOT_MATCH);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
public interface UserRepository extends JpaRepository<User, Long> {
boolean existsByUsername(String username);

Optional<User> findUserByUsername(String username);
Optional<User> findByUsername(String username);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.techeer.cokkiri.domain.user.dto.UserDto;
import com.techeer.cokkiri.domain.user.entity.User;
import com.techeer.cokkiri.domain.user.exception.UserPasswordWrongException;
import com.techeer.cokkiri.global.util.PasswordUtil;
import javax.servlet.http.HttpSession;
import lombok.AccessLevel;
Expand Down Expand Up @@ -36,8 +37,12 @@ public boolean isUserLogin() {
return getLoginUserId() != null;
}

public boolean isValidUser(UserDto.LoginRequest userRequest) {
User user = userService.findUserByUsername(userRequest.getUsername());
return passwordUtil.isSamePassword(userRequest.getPassword(), user.getPassword());
public boolean isValidPassword(UserDto.LoginRequest userRequest) {
User user = userService.findByUsername(userRequest.getUsername());
boolean isValidPassword =
passwordUtil.isSamePassword(userRequest.getPassword(), user.getPassword());
if (isValidPassword) {
return true;
} else throw new UserPasswordWrongException();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public User findUserById(long id) {
return userRepository.findById(id).orElseThrow(UserNotFoundException::new);
}

public User findUserByUsername(String username) {
return userRepository.findUserByUsername(username).orElseThrow(UserNotFoundException::new);
public User findByUsername(String username) {
return userRepository.findByUsername(username).orElseThrow(UserNotFoundException::new);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ public class RegExp {
public static final String PASSWORD_REGEXP =
"^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#!~$%^&-+=()])(?=\\S+$).{8,16}$";

public static final String USERNAME_REGEXP = "^[A-Za-z0-9]{5,20}$";
public static final String USERNAME_REGEXP = "^[A-Za-z0-9]{5,21}$";
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import lombok.*;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

@Getter
Expand All @@ -14,9 +14,9 @@
@EntityListeners(AuditingEntityListener.class)
@ToString
public class BaseEntity {
@CreatedDate private LocalDateTime createdAt;
@CreationTimestamp private LocalDateTime createdAt;
Copy link
Member

Choose a reason for hiding this comment

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

혹시 CreationTimestamp, UpdateTimestamp 같은거는 위에 AuditingEntityListener 가 필요할까요? 만약 필요없다면 지우고 설정파일도 필요가 없어질거같네요


@LastModifiedDate private LocalDateTime updatedAt;
@UpdateTimestamp private LocalDateTime updatedAt;

private boolean isDeleted;

Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/techeer/cokkiri/global/error/ErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ public enum ErrorCode {
UNAUTHORIZED_ACCESS_ERROR(403, "U003", "승인되지 않은 접근"),
USER_USERNAME_DUPLICATED(409, "U004", "회원 아이디 중복"),

USER_PASSWORD_NOT_MATCH(401, "U005", "비밀번호가 일치하지 않음"),

// Study
STUDY_DUPLICATION_ERROR(409, "S001", "스터디의 이름이 중복됨"),
STUDY_NOT_FOUND_ERROR(400, "S002", "스터디를 찾을 수 없음"),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.techeer.cokkiri.domain.user.Controller;

import static com.techeer.cokkiri.fixture.UserFixtures.USER_LOGIN_REQUEST;
import static com.techeer.cokkiri.global.result.ResultCode.USER_LOGIN_SUCCESS;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.content;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import com.techeer.cokkiri.domain.user.controller.UserController;
import com.techeer.cokkiri.domain.user.entity.User;
import com.techeer.cokkiri.domain.user.service.LoginService;
import com.techeer.cokkiri.domain.user.service.UserService;
import com.techeer.cokkiri.global.result.ResultResponse;
import com.techeer.cokkiri.global.util.JsonUtil;
import java.nio.charset.StandardCharsets;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;

@AutoConfigureMockMvc
@WebMvcTest(UserController.class)
public class UserControllerTest {

private final JsonUtil jsonUtil = new JsonUtil();

@MockBean UserService userService;

@MockBean LoginService loginService;

@Mock User mockUser;

private MockMvc mockMvc;

@BeforeEach
void setUp(WebApplicationContext applicationContext) {
mockMvc =
MockMvcBuilders.webAppContextSetup(applicationContext)
.addFilter(new CharacterEncodingFilter(StandardCharsets.UTF_8.name(), true))
.build();
}

// 미완성 테스트 - login메소드 오류
@Test
@DisplayName("로그인에 성공할 경우 ResultResponse(")
void loginTest() throws Exception {
// given - 회원가입
when(loginService.isValidPassword(any())).thenReturn(true);
when(userService.findByUsername(any())).thenReturn(mockUser);
when(mockUser.getId()).thenReturn(1L);

mockMvc
.perform(
post("/api/v1/users/login")
.contentType(MediaType.APPLICATION_JSON)
.content(jsonUtil.toJsonString(USER_LOGIN_REQUEST)))
.andExpect(status().isOk())
.andExpect(
MockMvcResultMatchers.content()
.string(jsonUtil.toJsonString(ResultResponse.of(USER_LOGIN_SUCCESS))))
.andDo(print()); // 전체 메시지 확인
System.out.println(content());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.techeer.cokkiri.domain.user.repository;

import static com.techeer.cokkiri.fixture.UserFixtures.DEFAULT_USER;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import com.techeer.cokkiri.domain.user.entity.User;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;

@DataJpaTest
public class UserRepositoryTest {

@Autowired private UserRepository userRepository;

private User user;

@BeforeEach
void saveUser() {}

@Test
@DisplayName("user의 존재여부를 username으로 확인한다.")
void existsByUsername() {
user = DEFAULT_USER;
userRepository.save(user);
assertTrue(userRepository.existsByUsername(user.getUsername()));
}

@Test
@DisplayName("username으로 user를 찾는다.")
void findByUsername() {
// given
user = DEFAULT_USER;
user = userRepository.save(user);
User savedUser = userRepository.findByUsername(user.getUsername()).orElseThrow();

// then
assertEquals(user, savedUser);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package com.techeer.cokkiri.domain.user.service;

import static com.techeer.cokkiri.fixture.UserFixtures.DEFAULT_USER;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;

import com.techeer.cokkiri.domain.user.dto.UserDto;
import com.techeer.cokkiri.domain.user.entity.User;
import com.techeer.cokkiri.domain.user.exception.UserPasswordWrongException;
import com.techeer.cokkiri.domain.user.mapper.UserMapper;
import com.techeer.cokkiri.domain.user.repository.UserRepository;
import com.techeer.cokkiri.global.util.PasswordUtil;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
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 UserServiceTest {

@Mock private UserRepository userRepository;

@Mock private UserMapper userMapper;

@Mock private PasswordUtil passwordUtil;

@Mock private UserService userService;

@InjectMocks private LoginService loginService;

private User user;
private UserDto.LoginRequest loginRequest;

@BeforeEach
void setup() {
user = DEFAULT_USER;

loginRequest =
UserDto.LoginRequest.builder()
.username(user.getUsername())
.password(user.getPassword())
.build();
}

@Nested
class loginTest {
@Test
@DisplayName("username은 존재하나 비밀번호가 다를 경우 로그인 실패한다.")
void wrongPassword() {
// given
when(userService.findByUsername(any())).thenReturn(user);
when(passwordUtil.isSamePassword(any(), any())).thenReturn(false);

// then
assertThrows(
UserPasswordWrongException.class,
() -> {
loginService.isValidPassword(loginRequest);
});
}

@Test
@DisplayName("올바른 username과 비밀번호 입력시 로그인 성공한다.")
void loginSuccess() {
// given
when(userService.findByUsername(any())).thenReturn(user);
when(passwordUtil.isSamePassword(any(), any())).thenReturn(true);

// when
boolean isValid = loginService.isValidPassword(loginRequest);

// then
assertTrue(isValid);
}
}
}
23 changes: 22 additions & 1 deletion src/test/java/com/techeer/cokkiri/fixture/UserFixtures.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,35 @@
package com.techeer.cokkiri.fixture;

import com.techeer.cokkiri.domain.user.dto.UserDto;
import com.techeer.cokkiri.domain.user.entity.User;

public class UserFixtures {
public static final User STUDY_MANAGER_FIXTURE =
User.builder()
.username("javaStudyManager")
.bio("자바를 좋아합니다.")
.imageUrl("url")
.nickname("javaMania")
.password("qwer123!")
.build();

public static final User DEFAULT_USER =
User.builder()
.username("DefaultUser1")
.bio("테스트용 디폴트 유저")
.nickname("default")
.password("Test1234!")
.build();

public static final UserDto.LoginRequest USER_LOGIN_REQUEST =
UserDto.LoginRequest.builder()
.username(DEFAULT_USER.getUsername())
.password(DEFAULT_USER.getPassword())
.build();

public static final UserDto.RegisterRequest USER_REGISTER_REQUEST =
UserDto.RegisterRequest.builder()
.username(DEFAULT_USER.getUsername())
.password(DEFAULT_USER.getPassword())
.nickname(DEFAULT_USER.getNickname())
.build();
}
12 changes: 12 additions & 0 deletions src/test/java/com/techeer/cokkiri/global/util/JsonUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.techeer.cokkiri.global.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JsonUtil {
private final ObjectMapper objectMapper = new ObjectMapper();

public String toJsonString(Object object) throws JsonProcessingException {
return objectMapper.writeValueAsString(object);
}
}
2 changes: 1 addition & 1 deletion src/test/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ spring:
generate-ddl: true
properties:
hibernate:
format_sql: true
format_sql: true