테스트 코드를 작성했을 때는 API를 바로 호출해서 만들었다.
하지만 시큐리티 옵션이 활성화되면서 인증된 사람만 API를 호출할 수 있게 되어 테슽트 코드마다 인증한 사용자가 호출한 것처럼 작동하도록 수정해야 한다.
일단 전체 테스트를 한 번 돌려보자
문제1
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'securityConfig' defined in file [..\SecurityConfig.class] :Unsatisfied dependency expressed through constructor parameter 0; org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type com.spaws.book.springboot.config.auth.CustomOAuth2UserService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
여러 오류 메시지 중 이런 메시지가 눈에 띌 것이다.
CustomOAuth2UserService를 생성하는데 필요한 소셜 로그인 관련 설정 값들이 없기 때문에 발생한다.
그렇다면 여기서 의문점이 생긴다.
application-oauth.properties의 값들을 읽어오지 못하는걸까?
-> test에 application.properties가 없으면 main의 설정을 그대로 가져온다.
여기서 문제는 자동으로 가져오는건 application.properties뿐이고 applicaiton-oauth.properties는 제외된다.
어떻게 해결해야 할까?
-> 테스트를 위한 application.properties를 만들자.
src/test/resources에 application.properties를 생성한다.
spring.jpa.show_sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
spring.h2.console.enabled=true
spring.mvc.hiddenmethod.filter.enabled=true
spring.session.store-type=jdbc
#Test OAuth
spring.security.oauth2.client.registration.google.client-id=test
spring.security.oauth2.client.registration.google.client-secret=test
spring.security.oauth2.client.registration.google.scope=profile, email
다시 jUnit을 실행시켜 보면 이번엔 302 FOUND Error을 확인할 수 있을 것이다.
임시로 만든 client-id=test, client-secret=test라는 인증되지 않은 사용자의 요청이기 때문이다.
이럴 때는 임의로 인증된 사용자를 추가해 API만 테스트할 수 있다.
build.gradle에 다음 코드를 추가한다.
testCompile("org.springframework.security:spring-security-test")
PostsApiControllerTest의 두 메소드에 임의 사용자 인증을 추가한다.
@Test
@WithMockUser(roles="USER")
public void Posts_등록() throws Exception {
...
}
@Test
@WithMockUser(roles="USER")
public void Posts_업데이트() throws Exception {
...
}
코드 설명 ▼
@WithMockUser(roles="USER")
- 인증된 모의 사용자를 만들어서 사용
- roles에 권한 추가 가능
- MockMvc에서만 작동
@SpringbootTest에서 MockMvc를 사용하는 방법
PostsApiControllerTest 수정
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class PostsApiControllerTest {
...
@Autowired
private WebApplicationContext context;
private MockMvc mvc;
@Before
public void setup() {
mvc = MockMvcBuilders
.webAppContextSetup(context)
.apply(springSecurity())
.build();
}
...
@Test
@WithMockUser(roles="USER")
public void Posts_등록() throws Exception {
//given
...
//when
mvc.perform(post(url)
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(new ObjectMapper().writeValueAsString(requestDto)))
.andExpect(status().isOk());
//then
List<Posts> all = postsRepository.findAll();
assertThat(all.get(0).getTitle()).isEqualTo(title);
assertThat(all.get(0).getContent()).isEqualTo(content);
}
@Test
@WithMockUser(roles="USER")
public void Posts_업데이트() throws Exception {
//given
...
//when
mvc.perform(post(url)
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(new ObjectMapper().writeValueAsString(requestDto)))
.andExpect(status().isOk());
//then
List<Posts> all = postsRepository.findAll();
assertThat(all.get(0).getTitle()).isEqualTo(expectedTitle);
assertThat(all.get(0).getContent()).isEqualTo(expectedContent);
}
}
문제2
java.lang.IllegalStateException: Failed to load ApplicationContext
...
No qualifying bean of type com.spaws.book.springboot.config.auth.CustomOAuth2UserService available
: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
1번과 똑같은 문제다?
언뜻 보면 문제 1번과 같은 오류인 것 같지만 조금 다른 점이 있다.
2번에서는 @WebMvcTest를 사용한다. 이 어노테이션은 CustomOAuth2UserService를 스캔하지 않는다.
@WebMvcTest
- 읽는 것: WebSecurityConfigurerAdapter, WebMvcConfigurer, @ControllerAdvice, @Controller
- 읽지 않는 것: @Repository, @Service, @Component, ...
결국 SecurityConfig는 읽었지만, SecurityConfig를 생성하기 위해 필요한 CustomOAuth2UserService를 읽을 수 없어서 에러가 발생한 것이다.
어떻게 해결해야 할까?
HelloControllerTest
@RunWith(SpringRunner.class)
@WebMvcTest(controllers = HelloController.class,
excludeFilters = {
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = SecurityConfig.class)
})
public class HelloControllerTest {
@Autowired
private MockMvc mvc;
@WithMockUser(roles="USER")
@Test
public void hello_리턴() throws Exception {
...
}
@WithMockUser(roles="USER")
@Test
public void helloDto_리턴() throws Exception {
...
}
}
일단 스캔 대상에서 SecurityConfig를 제외하고,
@WithMockUser를 통해 가짜 인증 사용자를 생성한다.
재실행하면 이번에는 java.lang.illegalStateException:Failed to load ApplicationContext가 뜰 것이다.
Application.java를 보면 @EnableJpaAuditing 어노테이션이 있는데, 이를 사용하기 위해선 최소 하나의 @Entity 클래스가 필요하다.
하지만 위 코드에서는 @WebMvcTest이다보니 Entity가 없다.
그래서 Application과 @EnableJpaAuditing을 분리해보겠다.
일단 Application에서 @EnableJapAuditing 어노테이션을 제거한다.
config폴더에 JpaConfig 클래스를 생성한다.
@Configuration
@EnableJpaAuditing
public class JpaConfig { }
다시 테스트를 수행하면 무사히 수행되는 것을 확인할 수 있다.
해당 게시글은 [ 스프링 부트와 AWS로 혼자 구현하는 웹 서비스 / 이동욱 ] 책을 따라한 것을 정리하기 위한 게시글입니다. 요약, 생략한 부분이 많으니 보다 자세한 설명은 책 구매를 권장합니다.
'Clone Coding > 스프링 부트와 AWS' 카테고리의 다른 글
[AWS RDS] db 환경 만들기 (0) | 2021.01.25 |
---|---|
[AWS EC2] 서버 환경 만들기 (0) | 2021.01.22 |
[OAuth 2] 네이버 로그인 연동하기 (0) | 2021.01.21 |
[OAuth 2] 구글 로그인 연동하기 (0) | 2021.01.21 |
[Mustache & Spring] 전체 조회 화면 만들기 (0) | 2021.01.19 |