```yaml
spring:
jpa:
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL5InnoDBDialect
show-sql: true
h2:
console:
enabled: true
session:
store-type: jdbc
# test oauth
security:
oauth2:
client:
registration:
google:
client-id: test
client-secret: test
scope: profile, email
```
// 스프링 시큐리티 테스트를 위한 여러 도구를 지원하는 의존성
testCompile('org.springframework.security:spring-security-test')
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class PostsApiControllerTest {
...
@Autowired
private WebApplicationContext context;
private MockMvc mvc;
// @Before
// 매번 테스트가 시작되기 전에 MockMvc 인스턴스를 생성한다
@Before
public void setUp() {
mvc = MockMvcBuilders
.webAppContextSetup(context)
.apply(springSecurity())
.build();
}
...
@Test
@WithMockUser(roles = "USER")
public void Posts_등록된다() throws Exception {
String title = "title";
String content = "content";
PostSaveRequestDto requestDto = PostSaveRequestDto.builder()
.title(title)
.content(content)
.author("author")
.build();
String url = "http://localhost:" + port + "/api/v1/posts";
// mvc.perform
// 생성된 MockMvc를 통해 API를 테스트한다.
mvc.perform(post(url)
.contentType(MediaType.APPLICATION_JSON_UTF8)
// 본문(Body) 영역은 문자열로 표현하기 위해 ObjectMapper를 통해 문자열 JSON으로 변환한다.
.content(new ObjectMapper().writeValueAsString(requestDto)))
.andExpect(status().isOk());
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 {
Posts savedPosts = postsRepository.save(Posts.builder()
.title("title")
.content("content")
.author("author")
.build());
Long updatedId = savedPosts.getId();
String expectedTitle = "title2";
String expectedContent = "content2";
PostsUpdateRequestDto requestDto = PostsUpdateRequestDto.builder()
.title(expectedTitle)
.content(expectedContent)
.build();
String url = "http://localhost:" + port + "/api/v1/posts/"+ updatedId;
mvc.perform(put(url)
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(new ObjectMapper().writeValueAsString(requestDto)))
.andExpect(status().isOk());
List<Posts> all = postsRepository.findAll();
assertThat(all.get(0).getTitle()).isEqualTo(expectedTitle);
assertThat(all.get(0).getContent()).isEqualTo(expectedContent);
}
}
@WithMockUser(roles = "USER")
- 인증된 모의(가짜) 사용자를 만들어서 사용한다.
- roles에 권한을 추가할 수 있다.
- 해당 어노테이션으로 ROLE_USER 권한을 가진 사용자가 API를 요철하는 것과 동일한 효과를 가지게 된다.
- @WithMockUser 는 MockMvc에서만 작동한다.
@Autowired
private WebApplicationContext context;
private MockMvc mvc;
// @Before
// 매번 테스트가 시작되기 전에 MockMvc 인스턴스를 생성한다
@Before
public void setUp() {
mvc = MockMvcBuilders
.webAppContextSetup(context)
.apply(springSecurity())
.build();
}
@Test
@WithMockUser(roles = "USER")
public void Posts_등록된다() throws Exception {
...
// mvc.perform
// 생성된 MockMvc를 통해 API를 테스트한다.
mvc.perform(post(url)
.contentType(MediaType.APPLICATION_JSON_UTF8)
// 본문(Body) 영역은 문자열로 표현하기 위해
// ObjectMapper를 통해 문자열 JSON으로 변환한다.
.content(new ObjectMapper().writeValueAsString(requestDto)))
.andExpect(status().isOk());
...
}
- 정리하면 WebSecurityConfigurerAdapter를 implements하는 SecurityConfig 클래스의 CustomOAuth2UserService를 읽지 못한다는 의미이다.
- 이 문제를 해결하기 위해서 @WebMvcTest의 스캔 대상에서 SecurityConfig를 제거해야한다.
@RunWith(SpringRunner.class)
@WebMvcTest(controllers = HelloController.class,
excludeFilters = {
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = SecurityConfig.class)
}
)
public class HelloControllerTest {
// @Autowired
// 스프링이 관리하는 Bean을 주입 받는 역할을 한다.
// private MockMvc mvc
// 웹 API를 테스트할 경우에에 사용한. HTTP GET,POST 등에 대한 테스트가 능가
@Autowired
private MockMvc mvc;
@Test
@WithMockUser(roles = "USER")
public void hello가_리턴된다() throws Exception {
...
}
@Test
@WithMockUser(roles = "USER")
public void helloDto가_리턴된다() throws Exception {
...
}
}
//@EnableJpaAuditing 제거
@SpringBootApplication
public class Application {
public static void main(String[] args) {
// SpringApplication.run 함수 : 내장 WAS(웹 어플리케이션 서버)를 실행한다. 외부의 별도 WAS(Tomcat 등)가 필요 없게된다
// 스프링 부트로 만들어진 Jar 파일(실행가능한 Java 패키징 파일)로 실행하면 된다.
// 내장 WAS는 언제 어디서나 같은 환경에서 스프링 부트를 배포할 수 있다.
SpringApplication.run(Application.class, args);
}
}
@Configuration
@EnableJpaAuditing
public class JpaConfig {
}
너무 감사합니다 바로 해결되네요 ㅎㅎ