@WebMvcTest๋ฅผ ํตํด Controller์ ๋ํ ํ ์คํธ๋ฅผ ์งํํ๋ ๊ฒฝ์ฐ Spring Security๋ฅผ ์ ์ฉํ์๋ค๋ฉด Security๊ฐ ์ ๊ณตํ๋ ๊ธฐ๋ณธ์ ์ธ Filter๋ค์ ๋ํ์ฌ ์ด๋ป๊ฒ ๋์ํด์ผ ํ๋์ง ๊ฑฑ์ ์ด ๋ ์๋ ์์ผ๋ฉฐ,
ํ ์คํธ ์งํ ๋์ค Error creating bean~~๋ฑ์ ์ค๋ฅ๊ฐ ๋ฐ์ํ ์๋ ์์ต๋๋ค.
์ด์ ๋ํ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ๋ํด ์์๋ณด๊ฒ ์ต๋๋ค.
์ด๋ค ์ค๋ฅ๊ฐ ๋ฐ์ํ๋์? ๐ง
์๋๋ ์ ๊ฐ ๋ฐ์์์ผฐ๋ ์ค๋ฅ์ด๋ฉฐ, ์ ๊ฐ ์์ฑํ ํด๋์ค์ ์ด๋ฆ์ด๋ Directory์ ๋ํ ๊ฒฝ๋ก๋ ~~ ๋ก ์ฒ๋ฆฌํ์์ต๋๋ค.
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name '~~' defined in file [~~]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type '~~' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋์? ๐ง
์ ๊ฐ ์์ฑํ ํ ์คํธ ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์์ต๋๋ค.
@WebMvcTest(controllers = MainTravelController.class)
class MainTravelControllerTest {
WebMvcTest์ ๋ํ ์ค๋ช ์ ์ดํด๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
WebMvcTest Anotation์ Spring MVC ์ปดํฌ๋ํธ์ ์ด์ ์ ๋ง์ถ์ด ํ ์คํธ๋ฅผ ์งํํ ์ ์๋ Anotation์ ๋๋ค.
์ด๋ฅผ ์ฌ์ฉํ๋ฉด ์คํ๋ง๋ถํธ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ์ฒด ๋กํ ํ๋ ๊ฒ์ด ์๋๋ผ
@Controller, @ControllerAdvice, @JsonComponent,Converter/GenericConverter, Filter, WebMvcConfigurer ๋ฐ HandlerMethodArgumentResolver ๋น์ด ์๋
@Component, @Service ๋๋ @Repository ๋น)์ ๊ด๋ จ๋ ๊ตฌ์ฑ๋ง ์ ์ฉ๋ฉ๋๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก @WebMvcTest ์ฃผ์์ด ๋ฌ๋ฆฐ ํ ์คํธ๋ Spring Security ๋ฐ MockMvc๋ ์๋ ๊ตฌ์ฑํฉ๋๋ค
์ค๋ช ์๋ ๋์์๋ฏ์ด Spring Security ๊ด๋ จ๋ ์ปดํฌ๋ํธ๋ ์๋ ๊ตฌ์ฑํฉ๋๋ค.
์ ์ Spring Security ๊ด๋ จ ์ปดํฌ๋ํธ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
์ด๋ Security ๊ด๋ จ๋ ์ปดํฌ๋ํธ์์ ์์กดํ๋ ๋ค๋ฅธ ๋น๋ค์ด @WebMvcTest์ ์ํด ๋ฑ๋ก๋์ง ์๋ ๋น๋ค์ด๋ผ๋ฉด ์ค๋ฅ๊ฐ ๋ฐ์ํ๊ฒ ๋ฉ๋๋ค.
์ด๋ป๊ฒ ํด๊ฒฐํ๋์? ๐ง
๋ฌด์์ ๊ด๋ จ๋ ์์กด์ฑ๋ค์ @Autowire๋ก ์ฃผ์ ๋ฐ์ผ๋ฉด @WebMvcTest๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ๋ณ๊ฒ ํ ์คํธ๋ฅผ ์งํํ๊ณ ์ ํ๋ ๋ชฉ์ ์ด ์ ๋งคํด์ง๋๋ค.
๊ทธ๋ผ ๊ด๋ จ๋ ์์กด์ฑ๋ค์ @MockBean๋ฑ์ ์ฌ์ฉํ์ฌ Mock ๊ฐ์ฒด๋ฅผ ์ฃผ์ ํด์ฃผ๋ฉด ์ด๋จ๊น์???
์คํ์ ๋์ง๋ง, ์ธ์ฆ์ด ํ์ํ url๋ก ์์ฒญ์ ๋ณด๋ธ ๊ฒฝ์ฐ 403 ์ค๋ฅ๊ฐ ๋น๋๋ค.
์ด๋ ์ธ์ฆ์ด ํ์ํ ์์ฒญ์ ๋ํด ์ธ์ฆ์ ์งํํ ๋ ํ์ํ ๋น๋ค์ Mock ๊ฐ์ฒด๊ฐ ์ ์ฅ๋์ด ์ธ์ฆ์ด ์ ๋๋ก ์งํ๋์ง ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
๋ ๋ค๋ฅธ ํด๊ฒฐ๋ฐฉ๋ฒ์ Spring Security ๊ด๋ จ ์ปดํฌ๋๋๋ค์ @WebMvcTest์ Component Scan ๋์์์ ์ ์ธ์ํค๋ ๋ฐฉ๋ฒ์ ๋๋ค.
๊ทธ๋ฌ๋ฉด ํด๊ฒฐ๋ ๊น์???
์ํ๊น๊ฒ๋ ์ฌ๊ธฐ์๋ 401 ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
์ด๋ Security๊ฐ ๊ธฐ๋ณธ์ ์ผ๋ก ์ ๊ณตํ๋ ์ธ์ฆ ํํฐ๋ค์ ์ํด ์ธ์ฆ์ด ๋์ง ์๊ธฐ์ ๋ฐ์ํ ๋ฌธ์ ์ ๋๋ค.
๊ด๋ จ ์์กด์ฑ์ ๋ํ Mock ๊ฐ์ฒด ์ฃผ์ , ๋๋ ํํฐ์์ ์ ์ธํ๋ ๋ฐฉ๋ฒ๋ค์์ 401, 403 ์ํ์ฝ๋๊ฐ ๋ฐํ๋๋ ์ค๋ฅ์ ๋ํ ํด๊ฒฐ๋ฐฉ๋ฒ์ ์์๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
401, 403 ์ค๋ฅ๊ฐ ๋ฐ์ํ๋๋ฐ์? ๐ง
@WithMockUser๋ฅผ ํตํด ํด๊ฒฐํฉ๋๋ค
@WithMockUser๋ ์ด๋ป๊ฒ ์ฐ๋์? ๐ง
WithMockUser๋ ๋ค์๊ณผ ๊ฐ์ด ์์ฑ๋์ด ์์ต๋๋ค.
์ด๋ฅผ ํตํด ์ํ๋ Role๊ณผ username, password ๋ฑ์ ์ค์ ํ ์ ์์ผ๋ฉฐ,
์ด๋ฌํ ์ ๋ณด๋ ๊ฒฐ๊ตญ SecurityContextHolder์ ์ ์ฅ๋ฉ๋๋ค.
๋ฐ๋ผ์ SecurityContextHolder๊ฐ ํ์ํ ์์ฒญ์ด๋, ๊ทธ๋ ์ง ์๋ ์ด์ ๋ํ ์ ๋ณด๋ฅผ ๊ฐ๋ฐ์๊ฐ ์ง์ ์ง์ ํ์ฌ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋ค์๊ณผ ๊ฐ์ด ํ ์คํธ ์ผ์ด์ค ์์ @WithMockUser๋ฅผ ๋ฌ์์ฃผ๋ฉด ํด๊ฒฐ๋ฉ๋๋ค.
์ถ๊ฐ์ ์ธ ์์ฑ์ด ํ์ํ ๊ฒฝ์ฐ ์ด์ ๋ํ ์ ๋ณด๋ฅผ ์ถ๊ฐํด์ฃผ์๋ฉด ๋ฉ๋๋ค.
Component Scan ๋์์์ ์ ์ธ VS Mock ๊ฐ์ฒด ๋ฑ์ ์์กด์ฑ ์ฃผ์ ๐ง
Component Scan ๋์์์ Security ๊ด๋ จ ์ปดํฌ๋ํธ๋ฅผ ์ ์ธํ๋ค๋ฉด, Role์ ๋ฐ๋ผ ์ ๊ทผ ๊ฐ๋ฅ ์ฌ๋ถ๊ฐ ๋ฌ๋ผ์ง๋ ๊ฒฝ์ฐ์ ๋ํ ํ ์คํธ ๋ฑ์ ํ ์ ์์ด์ง๋๋ค.
๊ทธ๋ฌ๋ ์ด๋ ์ค์ ์ ๋ณด์ ์ ์์ฑํ์์ผ๋ฉด Security์์ ์ ๊ณตํด ์ฃผ๋ ๊ธฐ๋ฅ์ด๊ธฐ์ ๋ฐ๋ก ํ์ธํ์ง ์์๋ ์ ์๋ํ ๊ฒ์ด๋ผ ๋ฏฟ์ ์ ์์ต๋๋ค.
๊ฐ์ธ ๋๋ฆ์ด์ง๋ง ์ ๋ ์ด์ ๋ํด์๋ ํ์ธ์ด ํ์ํ๋ค ์๊ฐํ๋๋ฐ, Security ๊ด๋ จ ์ค์ ์ด ์๋ชป๋์์ ์๋ ์๊ธฐ ๋๋ฌธ์ ์ด์ ๋ํ ํ ์คํธ๋ ์ด๋ฃจ์ด์ง๋ ๊ฒ์ด ๋ ์์ ํ๋ค๊ณ ์๊ฐํ๊ธฐ ๋๋ฌธ์ ๋๋ค.
๋ค๋ฅธ ์๊ฒฌ ์๋ค๋ฉด ๋๊ธ๋ก ์๋ ค์ฃผ์ธ์!! (์๋ฌด๋ ์๋ณด๊ฒ ์ง๋ง ใ )