회원 엔티티
@Entity
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Member extends BaseTimeEntity {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "MEMBER_ID")
private Long id;
@Column(nullable = false, unique = true)
private String email; // 아이디
@Column(nullable = false)
private String loginPw; // 비밀번호
@Column(nullable = false)
private String verifiedPw; // 비밀번호 확인
@Column(nullable = false, unique = true)
private String name; // 이름
private int age; // 나이
@Enumerated(EnumType.STRING)
@Column(nullable = false, length = 30)
private RoleType role; // 권한
/* 패스워드 암호화 관련 */
public void encodePassword(PasswordEncoder passwordEncoder){
this.loginPw = passwordEncoder.encode(loginPw);
}
/* 권한 부여 */
public void addMemberAuthority() {
this.role = RoleType.USER;
}
}
public enum RoleType {
USER, ADMIN
}
Member 엔티티는 위와 같습니다.
사용자는 회원가입을 진행하기 위해 이메일, 비밀번호, 비밀번호 확인, 이름, 나이를 입력해야 합니다.
회원 리포지토리
public interface MemberRepository extends JpaRepository<Member, Long> {
boolean existsByEmail(String email);
boolean existsByName(String name);
Optional<Member> findByEmail(String email);
}
회원 서비스
역할과 사용을 분리하기 위해 MemberService 인터페이스를 구현한 후, MemberServiceImpl이 해당 인터페이스를 구현합니다.
public interface MemberService {
boolean confirmEmail(String email);
boolean confirmName(String name);
void createMember(SignupRequestDTO signupRequestDTO);
Optional<Member> findByEmail(String email);
}
@Service
@RequiredArgsConstructor
@Transactional
public class MemberServiceImpl implements MemberService {
private final MemberRepository memberRepository;
private final PasswordEncoder passwordEncoder;
@Override
public boolean confirmEmail(String email) {
return memberRepository.existsByEmail(email);
}
@Override
public boolean confirmName(String name) {
return memberRepository.existsByName(name);
}
@Override
public void createMember(SignupRequestDTO signupRequestDTO) {
Member member = signupRequestDTO.toEntity();
member.addMemberAuthority();
member.encodePassword(passwordEncoder);
if(findByEmail(signupRequestDTO.getEmail()).isPresent()) {
}
}
@Override
public Optional<Member> findByEmail(String email) {
return Optional.empty();
}
}
회원 컨트롤러
@RestController
@RequiredArgsConstructor
@RequestMapping("/member")
public class MemberController {
private final MemberServiceImpl memberServiceImpl;
@GetMapping("/confirmEmail/{email}")
public ApiResult<?> confirmEmail(@PathVariable("email") String email) {
if (memberServiceImpl.confirmEmail(email)) {
throw new MemberException(ErrorStatus.MEMBER_EMAIL_ALREADY_EXISTS);
}
return ApiResult.onSuccess();
}
@GetMapping("/confirmName/{name}")
public ApiResult<?> confirmName(@PathVariable("name") String name) {
if (memberServiceImpl.confirmName(name)) {
throw new MemberException(ErrorStatus.MEMBER_NAME_ALREADY_EXISTS);
}
return ApiResult.onSuccess();
}
@PostMapping("/signup")
public ApiResult<?> signup(@RequestBody SignupRequestDTO requestDTO) {
SignupResponseDTO responseDTO = memberServiceImpl.createMember(requestDTO);
return ApiResult.onSuccess(responseDTO);
}
}
회원 서비스 테스트
class MemberServiceImplTest {
@Mock
private MemberRepository memberRepository;
@Mock
private PasswordEncoder passwordEncoder;
@InjectMocks
private MemberServiceImpl memberServiceImpl;
@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
}
@Test
@DisplayName("이메일 중복 확인")
void confirmEmail() {
String email = "test@example.com";
when(memberRepository.existsByEmail(email)).thenReturn(true);
boolean result = memberServiceImpl.confirmEmail(email);
assertTrue(result);
verify(memberRepository, times(1)).existsByEmail(email);
}
@Test
@DisplayName("이름(닉네임) 중복 확인")
void confirmName() {
String name = "testname";
when(memberRepository.existsByName(name)).thenReturn(true);
boolean result = memberServiceImpl.confirmName(name);
assertTrue(result);
verify(memberRepository, times(1)).existsByName(name);
}
@Test
@DisplayName("회원가입")
void createMember() {
SignupRequestDTO signupRequestDTO = SignupRequestDTO.builder()
.email("test@example.com")
.loginPw("password123")
.verifiedPw("password123")
.name("testname")
.age(25)
.build();
when(passwordEncoder.encode(any(String.class))).thenReturn("encodedPassword");
SignupResponseDTO responseDTO = memberServiceImpl.createMember(signupRequestDTO);
assertEquals(signupRequestDTO.getEmail(), responseDTO.getEmail());
assertEquals("encodedPassword", responseDTO.getLoginPw());
assertEquals(signupRequestDTO.getName(), responseDTO.getName());
assertEquals(signupRequestDTO.getAge(), responseDTO.getAge());
verify(memberRepository, times(1)).save(any(Member.class));
}
@Test
void findByEmail() {
String email = "test@example.com";
Member member = Member.builder().email(email).build();
when(memberRepository.findByEmail(email)).thenReturn(Optional.of(member));
Optional<Member> result = memberServiceImpl.findByEmail(email);
assertTrue(result.isPresent());
assertEquals(email, result.get().getEmail());
verify(memberRepository, times(1)).findByEmail(email);
}
}
회원 컨트롤러 테스트
class MemberControllerTest {
@Mock
private MemberServiceImpl memberServiceImpl;
@InjectMocks
private MemberController memberController;
private MockMvc mockMvc;
@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(memberController)
.setControllerAdvice(new MemberHandler())
.build();
}
@Test
@DisplayName("이메일 중복 확인")
void confirmEmail() throws Exception {
String email = "test@example.com";
when(memberServiceImpl.confirmEmail(email)).thenReturn(true);
mockMvc.perform(get("/member/confirmEmail/{email}", email))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.code").value(ErrorStatus.MEMBER_EMAIL_ALREADY_EXISTS.getCode()))
.andExpect(jsonPath("$.message").value(ErrorStatus.MEMBER_EMAIL_ALREADY_EXISTS.getMessage()));
}
@Test
@DisplayName("이름 중복 확인")
void confirmName() throws Exception {
String name = "testname";
when(memberServiceImpl.confirmName(name)).thenReturn(true);
mockMvc.perform(get("/member/confirmName/{name}", name))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.code").value(ErrorStatus.MEMBER_NAME_ALREADY_EXISTS.getCode()))
.andExpect(jsonPath("$.message").value(ErrorStatus.MEMBER_NAME_ALREADY_EXISTS.getMessage()));
}
@Test
@DisplayName("회원가입")
void signup() throws Exception {
SignupRequestDTO requestDTO = SignupRequestDTO.builder()
.email("test@example.com")
.loginPw("password123")
.verifiedPw("password123")
.name("testname")
.age(25)
.build();
SignupResponseDTO responseDTO = new SignupResponseDTO(requestDTO.toEntity());
when(memberServiceImpl.createMember(any(SignupRequestDTO.class))).thenReturn(responseDTO);
mockMvc.perform(post("/member/signup")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"email\":\"test@example.com\", \"loginPw\":\"password123\", \"verifiedPw\":\"password123\", \"name\":\"testname\", \"age\":25}"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.result.email").value("test@example.com"))
.andExpect(jsonPath("$.result.name").value("testname"))
.andExpect(jsonPath("$.result.age").value(25));
}
}
다음 글에서는 본격적으로 JWT 기반 로그인을 구현할 예정입니다.
'⚙️ Backend > Spring' 카테고리의 다른 글
JWT를 이용한 로그인 구현 (1) - 프로젝트 생성 (0) | 2024.06.23 |
---|