본문 바로가기

Dot Programming/Spring Clone

[스프링 웹앱 프로젝트 #19] 로그인 / 로그아웃 테스트

20. 로그인/ 로그아웃 테스트

테스트 요점 정리
 > 폼 서브밋 요청 (post)은 반드시 .with(csrf())를 추가할 것
 > .andExpect(authenticated()) 또는 .andExpect(unauthenticated())로 인증 여부를 확인할 수 있다.
 > 리다이렉트 응답은 .andExpect(status().is3xxRedirection())로 확인한다.
 > 리다이렉트 URL은 .andExpect(redirectedUrl())로 확인할 수 있다.
 > JUnit 5의 @BeforeEach@AfterEach
 > 임의로 로그인된 사용자가 필요한 경우에는 @WithMockUser

 

테스트코드 작성

@SpringBootTest
@AutoConfigureMockMvc
class MainControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private AccountService accountService;

    @Autowired
    private AccountRepository accountRepository;

    @BeforeEach
    void init(){
        SignUpForm signUpForm = new SignUpForm();
        signUpForm.setNickname("jongwon");
        signUpForm.setEmail("jong9712@naver.com");
        signUpForm.setPassword("12341234");
        accountService.processNewAccount(signUpForm);
    }

    // 회원정보가 중복으로 DB에 들어가니 삭제해줘야함
    @AfterEach
    void finish(){
        accountRepository.deleteAll();
    }

    @DisplayName("이메일로 로그인 성공")
    @Test
    public void login_with_email() throws Exception{
        // email이 아니라 nickname으로 인증하는 이유는
        // AccountUser에서 nickname과 password 반환해주기 때문에 그 값으로 인증
        mockMvc.perform(post("/login")
                        .param("username", "jong9712@naver.com")
                        .param("password", "12341234")
                        .with(csrf()))
                .andExpect(status().is3xxRedirection()) // redirect 발생
                .andExpect(redirectedUrl("/"))
                .andExpect(authenticated().withUsername("jongwon"));
     }

    @DisplayName("닉네임으 로그인 성공")
    @Test
    public void login_with_nickname() throws Exception{
        // email이 아니라 nickname 이유는
        // AccountUser에서 nickname과 password 반환해주기 때문에 그 값으로 인증
        mockMvc.perform(post("/login")
                .param("username", "jongwon")
                .param("password", "12341234")
                .with(csrf()))
                .andExpect(status().is3xxRedirection()) // redirect 발생
                .andExpect(redirectedUrl("/"))
                .andExpect(authenticated().withUsername("jongwon"));
    }

    @DisplayName("로그인 실패")
    @Test
    public void login_fail() throws Exception{
        mockMvc.perform(post("/login")
                .param("username", "1111")
                .param("password", "00000000")
                .with(csrf()))
                .andExpect(status().is3xxRedirection()) // redirect 발생
                .andExpect(redirectedUrl("/login?error"))
                .andExpect(unauthenticated());
    }

    @WithMockUser // security.user에 있는 가짜정보 넣어줌
    @DisplayName("로그아웃")
    @Test
    public void logout() throws Exception{
        mockMvc.perform(post("/logout")
                .with(csrf()))
                .andExpect(status().is3xxRedirection()) // redirect 발생
                .andExpect(redirectedUrl("/"))
                .andExpect(unauthenticated());
    }
}

 

로그아웃은 form servlet버튼으로 설정했다. 

 (server side쪽에서 구현할 필요 없음. spring security에서 알아서 처리해줌)

<!--spring security logout 핸들러가 처리-->
<form class="form-inline my-2 my-lg-0" action="#" th:action="@{/logout}" method="post">
       <button class="dropdown-item" type="submit">로그아웃</button>
</form>

 

@WithMockUser

Security.user를 선언한 내용을 가져와서 임의의 인증된 유저정보를 생성해줌

인증된 유저가 있는 어떤 로직이 있는 테스트를 할 때 유용하게 사용됨

@Getter
public class UserAccount extends User {

    // currentUser account와 일치
    private Account account;

    public UserAccount(Account account) {
        super(account.getNickname(), account.getPassword(), List.of(new SimpleGrantedAuthority("ROLE_USER")));
        this.account = account;
    }

}

 

 


참고

인프런 강의 - 스프링과 JPA 기반 웹 애플리케이션 개발