inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

Practical Testing: 실용적인 테스트 가이드

인증 관련 테스트 할 때 질문드립니다.

1286

비가싫어요

작성한 질문수 87

0

안녕하세요. 수업 내용과는 관련 없지만 테스트 코드를 짤 때 벽을 만나서 물어볼 곳이 마땅하지 않아 이 곳에 질문을 하게 됐습니다. 문제 있다면 바로 삭제하도록 하겠습니다.

프로젝트를 진행하고 있는데 Spring Security를 적용해서 하고 있습니다.

Service 쪽에서 Authentication 객체를 생성을 하고 JWT 를 만들어 줄 때 Authentication authentication = authenticationManagerBuilder.getObject()
.authenticate(new UsernamePasswordAuthenticationToken(username, password));

이렇게 생성을 하고 있습니다.

그래서 테스트코드를 짤 때

@Mock
private AuthenticationManagerBuilder authenticationManagerBuilder;

이런 식으로 Mocking 해주고

Authentication authentication = mock(Authentication.class);

given(authenticationManagerBuilder.getObject().authenticate(any())).willReturn(authentication);

이런 식으로 Stubbing 해주고 있는데요.

java.lang.NullPointerException: Cannot invoke "java.util.concurrent.atomic.AtomicBoolean.get()" because "this.building" is null

이런 에러가 나타나고 있습니다.

AuthenticationManagerBuilder를 좀 살펴보니 타고타고 가다보면 AbstractSecurityBuilder 라는 것을 상속하고 있더군요.

AbstractSecurityBuilder를 보면 private AtomicBoolean building = new AtomicBoolean(); 이런 필드가 있습니다. 에러에서 나온 building이 이걸 말하는 것 같습니다.

여기 나오는 building이 null 이어서

public final O getObject() {
if (!this.building.get()) {
throw new IllegalStateException("This object has not been built");
}
return this.object;
}

여기서 if 조건문을 탈 때 this.building이 null이기 때문에 NPE가 발생하는 것 같습니다.

 

AuthenticationManagerBuilder를 Mocking을 해서 이런 결과가 생기는것인가 하는 의심이 들고 있는 상황입니다.

혹시 이런 경우에는 어떤 식으로 Mocking을 하고 Stubbing을 해줘야 테스트가 통과될 지 궁금합니다.

구글링해도 자료가 거의 없고 gpt도 계속 이상한 말을 반복해서..ㅠㅠ 어쩔 수 없이 여기에 질문 올려봅니다.

도움 주시면 감사하겠습니다..!

spring tdd jpa mockito 소프트웨어-테스트 junit5

답변 2

0

박우빈

안녕하세요, JUNN님! :)

정확한 소스를 보지는 못해서 확답은 어렵지만, 말씀해주신 내용으로 추측해보자면 아마 mocking 때문인 것으로 보이는데요 ㅎㅎ

given(authenticationManagerBuilder.getObject().authenticate(any())).willReturn(authentication);

이 방식 대신에,

given(authenticationManagerBuilder.getObject()).willReturn(mockAuthenticationManager);
given(mockAuthenticationManager.authenticate(any())).willReturn(authentication);

이런 식으로 두 단계로 나눠서 한번 시도해보시길 바랍니다.

given(authenticationManagerBuilder.getObject().authenticate(any())).willReturn(authentication); 으로 한번에 stubbing을 건다고 해도, 실제로 적용되는 stubbing의 기준은 하나의 행위씩이기 때문에 결과적으로 authenticationManagerBuilder.getObject()에는 stubbing이 걸리지 않아서 실제 객체의 getObject() 로직을 수행하기 때문에 말씀하신 예외가 발생한 것으로 추측됩니다.

한번 시도해 보시고 말씀 주세요!
감사합니다 :)

0

인프런 AI 인턴

안녕하세요, 인프런 AI 인턴이에요.

일단 NullPointerException이 발생한 원인은 building 변수가 null이기 때문입니다. 이 변수는 Spring Security의 AbstractSecurityBuilder 클래스에서 초기화되며, 이 클래스는 AuthenticationManagerBuilder의 상위 클래스이기도 합니다.

Mocking과 Stubbing은 문제가 없어 보이지만, AbstractSecurityBuilder의 초기화를 제대로 수행하지 않아 building 변수가 null인 상태에서 getObject() 메소드가 호출되기 때문에 이런 에러가 발생하는 것 같습니다.

이 문제를 해결하려면 Mocking 및 Stubbing에 더해서 AbstractSecurityBuilder 클래스의 초기화에 필요한 다른 설정을 추가해야 합니다.

먼저, Mocking 문제를 해결하기 위해 다음과 같은 코드를 추가하면 됩니다.

@MockBean
private AuthenticationManager authenticationManager;

이 코드는 SecurityConfig 클래스에서는 AuthenticationManager를 빈으로 등록하고 있기 때문에, MockBean 어노테이션을 사용해서 이를 Mocking합니다.

그리고 Stubbing 문제를 해결하기 위해서는, Spring Security에서 사용하는 설정 파일에 빈으로 등록되어 있어야 하는 객체들을 정의하는 다른 설정을 추가적으로 제공할 필요가 있습니다.

보통의 경우 SecurityMockMvcConfigurers.springSecurity() 와 같은 기능을 사용해 Security 관련 config를 추가 등록하게 됩니다.

이러한 설정을 추가하면 Object가 빌드되어 생성될 때 building 변수가 null이 아닌 상태가 되면서, getObject() 메소드를 호출할 때도 문제 없이 수행할 수 있을 것입니다.

이상으로 인증 관련 테스트에 대한 질문에 답변을 드렸습니다. 추후 더 궁금한 점이 있으면 언제든지 다시 문의해주세요. 감사합니다.

private 상수 테스트 관련 질문

0

83

1

void는 어떻게 테스트하나요..? void로 애초에 코딩하면 안되나요??

0

126

2

커버리지는 어떻게 활용하시는지 궁금합니다.

0

161

2

테스트 문서화 질문입니다

0

105

2

단위테스트 질문이 있습니다

0

96

2

컨트롤러는 모킹을 한 이유가 궁금합니다.

0

103

2

ERD 가장자리에 있는 도메인 테스트 질문

0

89

2

DTO 검증 필드에 대한 테스트 코드 작성은 어디까지?

0

135

2

OrderCreateRequest DTO에 대해서 궁금한점

0

102

2

고전파의 테스트 대역 사용 대상, 공유 의존성

0

156

2

계층 관련 질문이 있습니다.

0

139

3

'코틀린'에서는 빌더를 따로 쓰지 않는데, 이 때는 어떻게 test fixture를 만드시는지 궁금합니다

1

124

2

혹시 update 로직은 어떻게 테스트하나요? (@Setter?)

0

135

2

단위테스트와 통합테스트의 경계가 궁금합니다.

0

229

2

Service+Repository 통합테스트 관련 질문입니다.

0

150

2

OrderControllerDocsTest 작성 해봤는데요. 날짜 형식이 이상하게 나와요

0

185

2

test 용 .yml

0

90

2

throws Exception

0

80

2

카페키오스크 클래스 문의 ,,

0

89

2

Rest docs 문서용 테스트코드를 따로 작성해야 되나요?

0

174

2

테스트 코드에서 필요한 생성자

0

138

1

tearDown 순서

0

116

2

@Builder 생성자 private

0

136

2

@DisplayName gradle / intellJ

0

93

2