반응형
테스트 코드 작성 중, AuthServiceTest에서 NullPointerException 발생
오류 메시지는 아래와 같다. 즉, application-jwt.properties에 담긴 jwt.secret 값을 @Value로 가져오는데, 테스트 코드에서는 해당 부분을 가져오지 못하여서 NullPointerException이 발생하였다.
의아한 점은 테스트 코드 상에서는 오류가 발생하지만, Postman으로 테스트 한 결과 정상적으로 Access, Refresh Token이 생성되는 것을 확인할 수 있었다.
1. 전체 코드
AuthServiceTest
NullPointerException이 발생한 테스트 코드
@SpringBootTest(properties = "spring.config.location=" +
"classpath:/application.yml" +
",classpath:/application-database-test.yml" +
",classpath:/application-jwt.properties")
@Transactional
class AuthServiceTest {
@Autowired
private AuthService authService;
@Autowired
private UserRepository userRepository;
@Autowired
private JwtTokenProvider jwtTokenProvider;
@BeforeEach
void init() {
// @Test , @RepeatedTest , @ParameterizedTest , @TestFactory 가 붙은 테스트 메소드가 실행하기 전에 실행된다.
// 각 테스트 메서드 전에 실행된다.
User userA = createUser("google_1", "userA@gmail.com", "google", "testA");
userRepository.save(userA);
}
@Test
@DisplayName("로그인 시 db에 사용자 정보가 있는 경우 정상 응답")
void signIn() {
/****** 오류가 발생한 부분 *******/
SignInResponseDto responseDto = authService.signIn("userA@gmail.com", "google");
assertThat(responseDto.getStatus()).isEqualTo(201);
}
}
JwtTokenProvider
@Slf4j
@RequiredArgsConstructor
@Component
public class JwtTokenProvider {
private UserRepository userRepository;
private SecretKey JWT_SECRET_TOKEN_KEY;
private static final long accessTokenExpiresIn = Duration.ofDays(1).toMillis(); // 만료시간 하루
private static final long refreshTokenExpiresIn = Duration.ofDays(7).toMillis(); // 만료시간 7일
public JwtTokenProvider(@Value("${jwt.secret.token}") String tokenKey) {
byte[] accessKeyBytes = Decoders.BASE64.decode(tokenKey);
JWT_SECRET_TOKEN_KEY = Keys.hmacShaKeyFor(accessKeyBytes);
System.out.println("생성자 호출됨");
}
// 테스트 코드 작성을 위해, LocalDate 값을 파라미터로 받도록 수정.
public String generateAccessToken(String userId, LocalDate currentDate) {
// LocalDate -> Date
Date date = Date.from(currentDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
return Jwts.builder()
.claim("user_id", userId)
.setSubject("Access_Token")
.setIssuedAt(date) // token 발급 시간
.setExpiration(new Date(date.getTime() + accessTokenExpiresIn))
.signWith(this.JWT_SECRET_TOKEN_KEY, SignatureAlgorithm.HS512)
.compact();
}
}
AuthService
@Transactional
public SignInResponseDto signIn(String email, String provider) {
List<User> userInDb = userRepository.findUserByEmailAndProvider(email, provider);
if (userInDb.size() > 0) {
// Created 응답과 함께 Access, Refresh token 발급
return SignInResponseDto.builder()
.status(201)
.accessToken(jwtTokenProvider.generateAccessToken(userInDb.get(0).getId(), LocalDate.now()))
.refreshToken(jwtTokenProvider.generateRefreshToken(userInDb.get(0).getId(), LocalDate.now()))
.build();
} else {
throw new CustomException(ErrorCode.USER_NOT_EXISTED);
}
}
2. 해결
ReflectionTestUtils.setField() 메서드를 오류가 난 메서드 내에 추가.
ReflectionTestUtils.setField(jwtTokenProvider, "JWT_SECRET_TOKEN_KEY", TEST_JWT_SECRET_TOKEN_KEY);
AuthServiceTest 수정(그 외 코드는 변경하지 않았음)
@SpringBootTest(properties = "spring.config.location=" +
"classpath:/application.yml" +
",classpath:/application-database-test.yml" +
",classpath:/application-jwt.properties")
@Transactional
class AuthServiceTest {
@Autowired
private AuthService authService;
@Autowired
private UserRepository userRepository;
@Autowired
private JwtTokenProvider jwtTokenProvider;
@Value("${jwt.secret.token}")
private String secretKey;
private SecretKey TEST_JWT_SECRET_TOKEN_KEY;
@BeforeEach
void init() {
// @Test , @RepeatedTest , @ParameterizedTest , @TestFactory 가 붙은 테스트 메소드가 실행하기 전에 실행된다.
// 각 테스트 메서드 전에 실행된다.
User userA = createUser("google_1", "userA@gmail.com", "google", "testA");
userRepository.save(userA);
byte[] accessKeyBytes = Decoders.BASE64.decode(secretKey);
TEST_JWT_SECRET_TOKEN_KEY = Keys.hmacShaKeyFor(accessKeyBytes);
}
@Test
@DisplayName("로그인 시 db에 사용자 정보가 있는 경우 정상 응답")
void signIn() {
ReflectionTestUtils.setField(jwtTokenProvider, "JWT_SECRET_TOKEN_KEY", TEST_JWT_SECRET_TOKEN_KEY);
// dto 검증
SignInResponseDto responseDto = authService.signIn("userA@gmail.com", "google");
assertThat(responseDto.getStatus()).isEqualTo(201);
}
}
2-1. 글 작성 이후 추가
- 이 부분 해결한 이후로, ReflectionTestUtils 부분을 제거해도 정상적으로 테스트가 통과한다.
2023.07.08 - [오류] - Spring Boot] java.lang.IllegalArgumentException: Key argument cannot be null
3. 기타(시도했으나 해결되지 않았음)
1.
@TestPropertySource(locations = "classpath:/application-jwt.properties")
2.
@ContextConfiguration(classes = JwtTokenProvider.class)
@TestPropertySource(locations = "classpath:/application-jwt.properties")
3.
@SpringBootTest(properties = "spring.config.location=" +
"classpath:/application.yml" +
",classpath:/application-database-test.yml" +
",classpath:/application-jwt.properties",
classes = {JwtTokenProvider.class})
참고 링크
1. https://stackoverflow.com/questions/52919296/springboot-2-junit5-null-with-value
2.
반응형
'Spring Boot > Test Code' 카테고리의 다른 글
Junit5] 테스트 코드 작성을 위한 서비스 코드 리팩토링 (0) | 2023.07.14 |
---|---|
Junit5] org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false (0) | 2023.07.08 |
Junit5] WebMvcTest: MockHttpServletResponse: Status = 401 Error message = Unauthorized (0) | 2023.07.01 |
Junit5] WebMvcTest (0) | 2023.06.09 |
Junit5] 테스트 코드 작성 원칙 정리 (0) | 2023.06.09 |