본문 바로가기
Framework/Spring

[Spring / ToyProject] Spring Security 설정 - 3_2

by wo__ongii 2025. 1. 16.
728x90

1. JwtService.java Test 코드 작성

1) 기본 구조

@SpringBootTest
@Transactional
class JwtServiceImplTest {

    @Autowired
    UserRepository userRepository;
    @Autowired
    UserEntity userEntity;
    @Autowired
    EntityManager em;

    @Value("${jwt.secret}")
    private String secret;

    @Value("${jwt.access.expiration}")
    private long accessTokenValidityInSeconds;

    @Value("${jwt.refresh.expiration}")
    private long refreshTokenValidityInSeconds;

    @Value("${jwt.access.header}")
    private String accessHeader;

    @Value("${jwt.refresh.header}")
    private String refreshHeader;

    private static final String ACCESS_TOKEN_SUBJECT = "AccessToken";
    private static final String REFRESH_TOKEN_SUBJECT = "RefreshToken";
    private static final String USERNAME_CLAIM = "email";
    private static final String BEARER = "Bearer";

    String username = "username";

    @BeforeEach
    public void init() {
        UserEntity user = UserEntity.builder().userEmail(username).userPwd("123456").userEmail("test@naver.com")
                .userNikname("usernick").build();
        userRepository.save(user);
        clear();
    }

    private void clear() {
        em.flush();
        em.clear();
    }
    
    //토큰의 유효성 확인, 검증
    private DecodedJWT getVerify(String token) {
        return JWT.require(Algorithm.HMAC512(secret)).build().verify(token);
    }
}

 

2) AccessToken, RefreshToken 발급 테스트

@Test
void createAccessToken_AccessToken_발급테스트() throws Exception {
    // given, when
    String accessToken = jwtService.createAccessToken(username);
    DecodedJWT verify = getVerify(accessToken);

    String subject = verify.getSubject();
    String findUsername = verify.getClaim(USERNAME_CLAIM).asString();

    // then
    assertThat(findUsername).isEqualTo(username);
    assertThat(subject).isEqualTo(ACCESS_TOKEN_SUBJECT);
}

@Test
void createAccessToken_RefreshToken_발급테스트() throws Exception{
    // given, when
    String refreshToken = jwtService.createRefreshToken();
    DecodedJWT verify = getVerify(refreshToken);
    String subject = verify.getSubject();
    String username = verify.getClaim(USERNAME_CLAIM).asString();

    // then
    assertThat(subject).isEqualTo(REFRESH_TOKEN_SUBJECT);
    assertThat(username).isNull(); //refreshToken은 username이 없어야 함
}

3) 토큰 유효성 테스트

@Test
void isTokenValid_토큰_유효성_검사() {
    // given
    String accessToken = jwtService.createAccessToken(username);
    String refreshToken = jwtService.createRefreshToken();

    // when, then
    assertThat(jwtService.isTokenValid(accessToken)).isTrue();
    assertThat(jwtService.isTokenValid(refreshToken)).isTrue();
}

 

4) RefreshToken 업데이트 테스트

@Test
void updateRefreshToken_refreshToken_업데이트() throws Exception {
    // given
    String refreshToken = jwtService.createRefreshToken();
    jwtService.updateRefreshToken(username, refreshToken);
    clear();
    Thread.sleep(5000);

    // when
    String reIssueRefreshToken = jwtService.createRefreshToken();
    jwtService.updateRefreshToken(username, reIssueRefreshToken);
    clear();

    // then
    assertThrows(NoSuchElementException.class, () -> userRepository.findByRefreshToken(refreshToken).get());
    assertThat(userRepository.findByRefreshToken(reIssueRefreshToken).get().getUserName()).isEqualTo(username);
}

 

5) RefreshToken 제거 테스트

@Test
void destoryRefreshToken_refreshToken_제거() throws Exception {
    // given
    String refreshToken = jwtService.createRefreshToken();
    jwtService.updateRefreshToken(username, refreshToken);
    clear();

    // when
    jwtService.destoryRefreshToken(username);
    clear();

    // then
    assertThrows(Exception.class, () -> userRepository.findByRefreshToken(refreshToken).get());
    UserEntity users = userRepository.findByUserName(username).get();
    assertThat(users.getRefreshToken()).isNull();
}

 

6) AccessToken, RefreshToken 헤더 설정 테스트

@Test
void setAccessTokenHeader_AccessToken_헤더_설정() throws Exception {
    // given
    MockHttpServletResponse mockHttpServletResponse = new MockHttpServletResponse();

    String accessToken = jwtService.createAccessToken(username);
    String refreshToken = jwtService.createRefreshToken();

    jwtService.setAccessTokenHeader(mockHttpServletResponse, accessToken);

    // when
    jwtService.sendAccessAndRefreshToken(mockHttpServletResponse, accessToken, refreshToken);

    // then
    String headerAccessToken = mockHttpServletResponse.getHeader(accessHeader);
    assertThat(headerAccessToken).isEqualTo(accessToken);
}

@Test
void setRefreshTokenHeader_RefreshToken_헤더_설정() throws Exception {
    // given
    MockHttpServletResponse mockHttpServletResponse = new MockHttpServletResponse();

    String accessToken = jwtService.createAccessToken(username);
    String refreshToken = jwtService.createRefreshToken();

    jwtService.setRefreshTokenHeader(mockHttpServletResponse, refreshToken);

    // when
    jwtService.sendAccessAndRefreshToken(mockHttpServletResponse, accessToken, refreshToken);

    // then
    String headerRefreshToken = mockHttpServletResponse.getHeader(refreshHeader);
    assertThat(headerRefreshToken).isEqualTo(refreshToken);
}

 

MockHttpServletResponse?
Spring의 테스트 프레임워크에서 제공하는 클래스 중 하나로, HTTP 응답을 모의(Mock)하는 데 사용된다. 실제 HTTP 응답을 보내지 않고, 테스트 환경에서 HTTP 응답의 상태를 확인하거나 설정할 수 있도록 한다.


1) 응답 객체 모의 : 실제 HTTP 요청/응답을 보내지 않고도 HTTP 응답을 테스트할 수 있도록 해준다. 여기서는 setAccessTokenHeader() 실행 시 응답 헤더에 accessToken을 설정할 수 있다.
2) 응답 헤더 설정 확인 : setAccessTokenHeader() 호출은 mockHttpServletResponse의 헤더에 accessToken을 설정하는 코드이다. 이후 mockHttpServletResponse.getHeader()로 헤더값을 가져와 올바르게 설정되었는지 검증할 수 있다.

7) 토큰 전송 테스트

@Test
void sendAccessAndRefreshToken_토큰_전송() {
    // given
    MockHttpServletResponse mockHttpServletResponse = new MockHttpServletResponse();

    String accessToken = jwtService.createAccessToken(username);
    String refreshToken = jwtService.createRefreshToken();

    // when
    jwtService.sendAccessAndRefreshToken(mockHttpServletResponse, accessToken, refreshToken);

    // then
    String headerAccessToken = mockHttpServletResponse.getHeader(accessHeader);
    String headerRefreshToken = mockHttpServletResponse.getHeader(refreshHeader);

    assertThat(headerAccessToken).isEqualTo(accessToken);
    assertThat(headerRefreshToken).isEqualTo(refreshToken);
}

 

8) 토큰 추출 테스트

@Test
void extractAccessToken_AccessToken_추출() throws Exception {
    // given
    String accessToken = jwtService.createAccessToken(username);
    String refreshToken = jwtService.createRefreshToken();
    HttpServletRequest request = setRequset(accessToken, refreshToken);

    // when
    String extractAccessToken = jwtService.extractAccessToken(request)
            .orElseThrow(() -> new Exception("예외 - Access 토큰이 없습니다."));

    // then
    assertThat(extractAccessToken).isEqualTo(accessToken);
    assertThat(getVerify(extractAccessToken).getClaim(USERNAME_CLAIM).asString()).isEqualTo(username);
}

@Test
void extractRefreshToken_RefreshToken_추출() throws Exception {
    // given
    String accessToken = jwtService.createAccessToken(username);
    String refreshToken = jwtService.createRefreshToken();
    HttpServletRequest request = setRequset(accessToken, refreshToken);

    // when
    String extractRefreshToken = jwtService.extractRefreshToken(request)
            .orElseThrow(() -> new Exception("예외 - Refresh 토큰이 없습니다."));

    // then
    assertThat(extractRefreshToken).isEqualTo(refreshToken);
    // refreshToken은 username 없음
    assertThat(getVerify(extractRefreshToken).getSubject()).isEqualTo(REFRESH_TOKEN_SUBJECT);
}

private HttpServletRequest setRequset(String accessToken, String refreshToken) throws IOException {
    MockHttpServletResponse mockHttpServletResponse = new MockHttpServletResponse();
    jwtService.sendAccessAndRefreshToken(mockHttpServletResponse, accessToken, refreshToken);
    String headerAccessToken = mockHttpServletResponse.getHeader(accessHeader);
    String headerRefreshToken = mockHttpServletResponse.getHeader(refreshHeader);

    MockHttpServletRequest mockHttpServletRequest = new MockHttpServletRequest();

    mockHttpServletRequest.addHeader(accessHeader, BEARER + headerAccessToken);
    mockHttpServletRequest.addHeader(refreshHeader, BEARER + headerRefreshToken);

    return mockHttpServletRequest;
}

 

9) username 추출 테스트

@Test
void extractUsername_username_추출() throws Exception {
    // given
    String accessToken = jwtService.createAccessToken(username);
    String refreshToken = jwtService.createRefreshToken();
    HttpServletRequest request = setRequset(accessToken, refreshToken);
    String requestAccessToken = jwtService.extractAccessToken(request)
            .orElseThrow(() -> new Exception("예외 - 토큰이 없습니다."));

    // when
    String extractUsername = jwtService.extractUsername(requestAccessToken)
            .orElseThrow(() -> new Exception("예외 - 토큰 없음"));

    // then
    assertThat(extractUsername).isEqualTo(username);
}

 

 

 

 

 

[출처: https://ttl-blog.tistory.com/272#JwtService%20%EC%9E%91%EC%84%B1-1]

728x90
반응형