25. 프로필 수정 테스트
인증된 사용자가 접근할 수 있는 기능 테스트하기
> 실제 DB에 저장되어 있는 정보에 대응하는 인증된 Authentication이 필요하다.
> @WithMockUser로는 처리할 수 없다
인증된 사용자를 제공할 커스텀 어노테이션 만들기
> @WithAccount
커스텀 어노테이션
@WithSecurityContext
SecurityContextFactory 구현
참고문서
https://docs.spring.io/spring-security/site/docs/current/reference/html5/#test
Junit5 - SpringSecurity Test 버그
@SpringBootTest
@AutoConfigureMockMvc
class SettingsControllerTest {
@Autowired
MockMvc mockMvc;
@Autowired
AccountService accountService;
@Autowired
AccountRepository accountRepository;
@BeforeEach
void beforeEach(){
SignUpForm signUpForm = new SignUpForm();
signUpForm.setNickname("loosie");
signUpForm.setEmail("loosie@naver.com");
signUpForm.setPassword("12341234");
accountService.processNewAccount(signUpForm);
}
@WithUserDetails(value = "loosie", setupBefore = TestExecutionEvent.TEST_EXECUTION)
@DisplayName("프로필 수정하기 - 입력값 정상")
@Test
void updateProfile() throws Exception{
String bio = "짧은 소개를 수정하는 경우";
mockMvc.perform(post(SettingsController.SETTINGS_PROFILE_URL)
.param("bio", bio)
.with(csrf()))
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrl(SettingsController.SETTINGS_PROFILE_URL))
.andExpect(flash().attributeExists("message"));
Account loosie = accountRepository.findByNickname("loosie");
assertEquals(bio, loosie.getBio());
}
}
BUG
beforeEach()실행 되기 전에 WithUserDetail이 실행이 되어서 유저 값을 못받아온다
'setupBefore = TestExecutionEvent.TEST_EXECUTION' beforeEach와 Test코드 중간에 실행하게 해주는 기능인데
이를 선언해주어도 test는 실패한다.
> 오픈소스 풀리퀘날려도 됨
프로필 수정하는 테스트 작성
그래서 @WithUserDetails말고 @WithSecurityContext를 사용할 것이다.
@Interface WithUser 생성
@Retention(RetentionPolicy.RUNTIME)
@WithSecurityContext(factory = WithAccountSecurityContextFactory.class)
public @interface WithAccount {
String value();
}
유저 데이터폼을 저장 후 인증된 회원정보를 context에 담는 클래스 생성
WithAccountSecurityContextFactory.class
@RequiredArgsConstructor
public class WithAccountSecurityContextFactory implements WithSecurityContextFactory<WithAccount> {
private final AccountService accountService;
@Override
public SecurityContext createSecurityContext(WithAccount withAccount) {
String nickname = withAccount.value();
SignUpForm signUpForm = new SignUpForm();
signUpForm.setNickname(nickname);
signUpForm.setEmail(nickname + "@naver.com");
signUpForm.setPassword("12341234");
accountService.processNewAccount(signUpForm);
UserDetails principal = accountService.loadUserByUsername(nickname);
Authentication authentication = new UsernamePasswordAuthenticationToken(principal, principal.getPassword(), principal.getAuthorities());
SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(authentication);
return context;
}
}
Test 실행
(@AfterEach : 테스트 실행 후 @WithAccount로 생성된 인증회원정보를 삭제해 줌)
@SpringBootTest
@AutoConfigureMockMvc
class SettingsControllerTest {
@Autowired
MockMvc mockMvc;
@Autowired
AccountRepository accountRepository;
// 테스트 실행 후에는 테스트로 만든 계정을 다시 지워야함
@AfterEach
void afterEach(){
accountRepository.deleteAll();
}
@WithAccount("loosie")
@DisplayName("프로필 수정하기 - 입력값 정상")
@Test
void updateProfile() throws Exception{
String bio = "짧은 소개를 수정하는 경우";
mockMvc.perform(post(SettingsController.SETTINGS_PROFILE_URL)
.param("bio", bio)
.with(csrf()))
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrl(SettingsController.SETTINGS_PROFILE_URL))
.andExpect(flash().attributeExists("message"));
Account loosie = accountRepository.findByNickname("loosie");
assertEquals(bio, loosie.getBio());
}
}
프로필 수정값 에러 테스트 작성
bio 35자 제한
@WithAccount("loosie")
@DisplayName("프로필 수정하기 - 입력값 에러")
@Test
void updateProfile_error() throws Exception{
String bio = "35자 이상 에러 길게 소개를 수정하는 경우길게 소개를 수정하는 경우길게 소개를 수정하는 경우길게 소개를 수정하는@Length(max = 50)@Length(max = 50)@Length(max = 50)@Length(max = 50)@Length(max = 50)@Length(max = 50) 경우길게 소개를 수정하는 경우";
mockMvc.perform(post(SettingsController.SETTINGS_PROFILE_URL)
.param("bio", bio)
.with(csrf()))
.andExpect(status().isOk())
.andExpect(view().name(SettingsController.SETTINGS_PROFILE_VIEW_NAME))
.andExpect(model().attributeExists("account"))
.andExpect(model().attributeExists("profile"))
.andExpect(model().hasErrors());
Account loosie = accountRepository.findByNickname("loosie");
assertNull(loosie.getBio());
}
마지막으로 프로필 수정폼 가져오는 테스트 작성
인증된 유저 객체가 없으면 에러
@WithAccount("loosie") // 인증된 유저정보 없으면 오류
@DisplayName("프로필 수정 폼")
@Test
void updateProfileForm() throws Exception{
mockMvc.perform(get(SettingsController.SETTINGS_PROFILE_URL))
.andExpect(status().isOk())
.andExpect(model().attributeExists("account"))
.andExpect(model().attributeExists("profile"));
}
참고
인프런 강의 - 스프링과 JPA 기반 웹 애플리케이션 개발
'Dot Programming > Spring Clone' 카테고리의 다른 글
[스프링 웹앱 프로젝트 #27 #28] 패스워드 수정 및 테스트 (0) | 2021.03.04 |
---|---|
[스프링 웹앱 프로젝트 #26] 프로필 이미지 변경 (0) | 2021.03.04 |
[스프링 웹앱 프로젝트 #24] 프로필 수정 처리 (0) | 2020.12.21 |
[스프링 웹앱 프로젝트 #23] 프로필 수정 폼 (0) | 2020.12.17 |
[스프링 웹앱 프로젝트 #22] Open Entitymanager (또는 Session) In View 필터 (0) | 2020.12.15 |