Loading...

Spring/Tistory / / 2022. 6. 7. 12:02

블로그-V3. 유저 컨트롤러 통합 테스트

반응형

컨트롤러는 통합 테스트하자.

testRestTemplate.exchange("/join-form", HttpMethod.GET, null, String.class);

 

assertEquals는 레퍼런스 주소까지 비교한다.

// RestController 테스트는 통합테스트로 하면 편하다 -> TestRestTemplate
// Controller 테스트는 모델 값 확인이 안되기 때문에 WebMvcTest 사용해야함 MockMvc 필요
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class UserControllerTest {

    @Autowired
    private TestRestTemplate testRestTemplate;

    @Test
    public void joinForm_테스트() {
        ResponseEntity<String> responseEntity = testRestTemplate.exchange("/join-form", HttpMethod.GET, null,
                String.class);

        assertEquals(200, responseEntity.getStatusCodeValue());
        assertEquals("text/html;charset=UTF-8", responseEntity.getHeaders().getContentType().toString());
    }

    @Test
    public void loginForm_테스트() {
        ResponseEntity<String> responseEntity = testRestTemplate.exchange("/login-form", HttpMethod.GET, null,
                String.class);

        assertEquals(200, responseEntity.getStatusCodeValue());
        assertEquals("text/html;charset=UTF-8", responseEntity.getHeaders().getContentType().toString());
    }

    @Test
    public void updateForm_테스트() {
        // given
        Integer id = 1;

        // when
        ResponseEntity<String> responseEntity = testRestTemplate.exchange("/s/user/id", HttpMethod.GET, null,
                String.class);

        // then
        assertEquals(200, responseEntity.getStatusCodeValue());
        assertEquals("text/html;charset=UTF-8", responseEntity.getHeaders().getContentType().toString());
    }

    public void passwordResetForm_테스트() {
        // when
        ResponseEntity<String> responseEntity = testRestTemplate.exchange("/user/password-reset-form", HttpMethod.GET,
                null,
                String.class);

        // then
        assertEquals(200, responseEntity.getStatusCodeValue());
        assertEquals("text/html;charset=UTF-8", responseEntity.getHeaders().getContentType().toString());
    }

    public void profileImgUpdate_테스트() {
    }

    public void findPassword_테스트() {
    }

    public void join_테스트() {
    }

    public void usernameCheck_테스트() {
    }

    public void passwordReset_테스트() {
    }

}

 

RestController 테스트는 통합테스트로 하면 편하다.

TestRestTemplate 사용하면 된다.

 

Controller 테스트는 MockMvc가 필요하다.

얘가 있어야 model 값 검증이 가능하다.

 

이때 WebMvcTest(컨트롤러 앞단)를 쓸지, SpringbootTest(다띄움)를 쓸지는 메모리에 무엇을 올리는지에 따라 다르다.

 

SpringbootTest + MockMvc -> 메모리에 다 올림

: 포스트맨으로 테스트하는 것처럼 테스트 가능

 

WebMvcTest + MockMvc -> 컨트롤러 앞단만 메모리에 올리겠다는 것

: 단위 테스트 목적이 젤 작게 테스트하는거니까 최소한으로 메모리에 올리기

 

 

@WebMvcTest는 내부적으로 MockMvc 를 들고있어서 바로 사용이 가능한데,

@SpringbootTest 는 안들고있어서 직접 어노테이션 걸어줘야한다.

 

 


 

클래스가 갖고있는 static한 변수나 메서드를 내가 갖고있는것처럼 사용이 가능하게 만드는 문법이다.

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
ResultActions resultActions = mockMvc.perform(MockMvcRequestBuilders.get("/join-form"));
↓
ResultActions resultActions = mockMvc.perform(get("/join-form"));

MockMvc가 들고있는 두가지 static 기능

 

buildersmatchers

 


 

BDD Mockito 패턴 (given-when-then)

@Test
public void joinForm_테스트() throws Exception {
    // given

    // when
    ResultActions resultActions = mockMvc.perform(get("/join-form"));

    // then
    resultActions.andExpect(status().isOk());
}

 


 

updateForm 시큐리티가 낚아챘기 때문에 리다이렉션 되었다.

인증이 필요한 주소이기 때문에 로그인하라고!

 

로그인 해놓고 테스트하는 방법

 

MockMvc를 IoC 컨테이너에 띄운게 아니라 내가 직접 new 하는 것

 

SecurityMockMvcConfigurers로 시큐리티가 뜨게 되고

@WithMockUser가 뜨면 가짜 유저를 만들어준다.

 

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
// @AutoConfigureMockMvc // MockMvc를 IoC에 띄워라
public class UserControllerTest {

    // @Autowired
    private MockMvc mockMvc;

    @Autowired
    private WebApplicationContext context;

    @BeforeEach
    public void setup() {
        mockMvc = MockMvcBuilders
                .webAppContextSetup(context) // spring의 환경을 알고있어야 set할텐데
                .apply(SecurityMockMvcConfigurers.springSecurity())
                .build();
    }
    
    @WithMockUser
    @Test
    public void updateForm_테스트() throws Exception {
        // given
        Integer id = 1;

        // when
        ResultActions resultActions = mockMvc.perform(get("/s/user/" + id));

        // then
        resultActions
                .andExpect(status().isOk())
                .andExpect(content().contentType("text/html;charset=UTF-8"));
    }
}

 

그러면 머스태치에서 principal이 null이라서 오류가 뜨는데

이거만 가짜로 만들어서 넣어주면 된다.

 

principal은 어디에 넣어주면 될까?

 


 

스프링 서버가 실행되는순간 컴포넌트 스캔을 해서 필요한것들을 메모리에 띄우지.

 

커넥션 풀링기법을 사용하는데 사용자가 요청할때마다 만들었다 지웠다 하기 귀찮으니까

request를 미리 (컴퓨터의 성능에 따라) 객체를 만들어둔다.

 

request 4개를 만들어두면 동시접속이 4명까지 된다.

 

request는 클라이언트의 임시 저장소이다.

 

DB도 커넥션 객체가 있는데 3개라면 4명까지 접속은 가능하지만 3명까지 동시에 DB에 접근가능.

 

 

세션 공간도 있는데 여긴 하나의 공간.

여기서 principal은 session 영역에서 들고온다.

내가 principal을 세션에만 넣으면 찾아서 쓸 수 있다.

가짜로 넣어주면 된다.

 

 

 

 

스프링 시큐리티를 쓰면 이거 고정

// @Autowired
private MockMvc mockMvc;

@Autowired
private WebApplicationContext context;

@BeforeEach
public void setup() {
    mockMvc = MockMvcBuilders
            .webAppContextSetup(context) // spring의 환경을 알고있어야 set할텐데
            .apply(SecurityMockMvcConfigurers.springSecurity())
            .build();
}

 

스프링 시큐리티를 쓰면 인증 객체가 필요할 때 @WithMockUser 붙여준다.

이렇게 끝나면 되는데 혹시나 뷰에서 세션이 필요할 때는 MockHttpSession 에 principal 담아주기.

 

@WithMockUser // 가짜 인증 객체 -> 시큐리티 통과 위해서
@Test
public void updateForm_테스트() throws Exception {
    // given
    Integer id = 1;

    User principal = User.builder()
            .id(1)
            .username("ssar")
            .password("1234")
            .email("ssar@nate.com")
            .profileImg(null)
            .build();

    MockHttpSession session = new MockHttpSession();
    session.setAttribute("principal", principal);

    // when
    ResultActions resultActions = mockMvc.perform(get("/s/user/" + id).session(session));

    // then
    resultActions
            .andExpect(status().isOk())
            .andExpect(content().contentType("text/html;charset=UTF-8"));
}

 

 

[출처]

 

https://cafe.naver.com/metacoding

 

메타코딩 : 네이버 카페

코린이들의 궁금증

cafe.naver.com

메타 코딩 유튜브

https://www.youtube.com/c/%EB%A9%94%ED%83%80%EC%BD%94%EB%94%A9

 

메타코딩

문의사항 : getinthere@naver.com 인스타그램 : https://www.instagram.com/meta4pm 깃헙 : https://github.com/codingspecialist 유료강좌 : https://www.easyupclass.com

www.youtube.com

 
반응형