상품 공급 시스템 - 회원 관련 기능

오류 수정

매핑 오류

3일차에 구현했던 닉네임 중복검사 기능의 DAO에서 오류를 발견했다.
실제로 DB에서는 회원의 id값만 가져오지만 회원 테이블의 모든 컬럼의 값을 가져온 것처럼 Member 객체를 만들고 있었다.
회원이 존재하는 상황에서 테스트를 하지 않았기 때문에 실행되지 않았던 부분이다

닉네임 중복검사 오류

아래와 같이 수정했다. (commit 9450fd)

commit 9450fd

재가입에 대한 고려

이미 탈퇴한(비활성화된) 회원이 재가입하는 경우에 대한 고려가 전혀 없었다. 서비스 정책을 한 명의 사람이 탈퇴와 재가입을 무한정 할 수 있다 라고 설정하고 이에 대응할 수 있도록 수정했다.
기존에는 nickname과 email 값이 unique하다고 가정했지만 위의 정책대로라면 닉네임과 이메일로 회원을 조회하면 탈퇴한 n개의 데이터와 현재 활성화된 회원 1명 또는 0명이 조회될 수 있다.

해당 닉네임 또는 이메일을 사용중인 활성화된 회원이 있는지 확인하기 위해 DAO가 수행하는 쿼리를 다음과 같이 수정했다. (commit 5313e3)

SELECT member_id FROM member WHERE nickname = ? AND enabled = true

회원가입 진행 과정

회원가입이 진행되는 흐름은 다음과 같다. 회색은 클라이언트, 검은색은 서버에서 진행되는 과정이다.

회원가입 흐름

필요한 API는 다음과 같다.

이메일 사용 가능여부 확인

해당 닉네임을 사용하고 활성화된 회원이 존재한다면 사용 불가능하다고 판단하고 없다면 사용 가능하다고 판단한다.

서비스

public ResponseStatus checkEmailAlreadyExists(String email) {
    Optional<Long> memberId;
    try {
        memberId = memberDao.findEnabledMemberIdByEmail(email);
    } catch (SQLException e) {
        return DATABASE_EXCEPTION;
    }
    if (memberId.isPresent())
        return EMAIL_ALREADY_EXISTS;
    else
        return USABLE_EMAIL;
}

DAO

public Optional<Long> findEnabledMemberIdByEmail(String email) throws SQLException{
    String query = "SELECT member_id FROM member WHERE email = ? AND enabled = true";
    try( Connection conn = dataSource.getConnection();
         PreparedStatement stmt = conn.prepareStatement(query); ) {
        stmt.setString(1, email);
        try (ResultSet rs = stmt.executeQuery()) {
            Long memberId = null;
            if (rs.next())
                memberId = rs.getLong("member_id");
            return Optional.ofNullable(memberId);
        } catch (SQLException executeQueryException) {
            throw executeQueryException;
        }
    } catch (SQLException connectionAndStatementException) {
        throw connectionAndStatementException;
    }
}

테스트

닉네임 중복검사와 동일한 흐름이다. DAO 객체는 mock으로 만들고 이미 사용중인 경우와 사용할 수 있는 경우로 나누어 테스트를 작성했다.

@Test
void 이미_가입된_이메일_가입_시도() throws SQLException {
    // given
    Optional<Long> retValOfMockedMemberDao = Optional.of(0l);
    Mockito.when(memberDao.findEnabledMemberIdByEmail(any(String.class)))
            .thenReturn(retValOfMockedMemberDao);
    // when
    ResponseStatus status = signupService.checkEmailAlreadyExists("foo@bar.com");
    // then
    Assertions.assertThat(status).isEqualTo(EMAIL_ALREADY_EXISTS);
}

@Test
void 사용_가능한_이메일_가입_시도() throws SQLException {
    // given
    Optional<Long> retValOfMockedMemberDao = Optional.ofNullable(null);
    Mockito.when(memberDao.findEnabledMemberIdByEmail(any(String.class)))
            .thenReturn(retValOfMockedMemberDao);
    // when
    ResponseStatus status = signupService.checkEmailAlreadyExists("foo@bar.com");
    // then
    Assertions.assertThat(status).isEqualTo(USABLE_EMAIL);
}

Comments