인프런 커뮤니티 질문&답변

임도현님의 프로필 이미지

작성한 질문수

호돌맨의 요절복통 개발쇼 (SpringBoot, Vue.JS, AWS)

게시글 조회 5 - 페이징 처리 (QueryDSL)

테스트 전체 실행시 id 값이 4부터 시작하는 현상

작성

·

1.1K

3

@SpringBootTest
@AutoConfigureMockMvc
@PropertySource("classpath:messages.properties")
class PostControllerTest {

    @Autowired
    private ObjectMapper mapper;
    @Autowired
    private Environment environment;
    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private PostRepository postRepository;


    @BeforeEach
    void clean() {
        postRepository.deleteAll();
    }

    @Test
    @DisplayName("/posts 요청시 Hello World를 출력한다.")
    void test() throws Exception {

        // given
        PostCreate request = PostCreate.builder()
                .title("제목입니다.")
                .content("내용입니다.")
                .build();

        String json = mapper.writeValueAsString(request);

        // expected
        mockMvc.perform(MockMvcRequestBuilders.post("/posts")
                        .contentType(MediaType.APPLICATION_JSON)
                                .content(json)
//                        .content("{\"title\": \"hithere\", \"content\": \"blah\"}")
                )
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andExpect(MockMvcResultMatchers.content().string(""))
                .andDo(print());

    }

    @Test
    @DisplayName("/posts 요청시 title 값은 필수다.")
    void test2() throws Exception {

        Class<? extends PostControllerTest> aClass = getClass();
        ClassLoader classLoader = getClass().getClassLoader();
        URL resource = classLoader.getResource("messages.properties");


        // given
        PostCreate request = PostCreate.builder()
                .content("내용입니다.")
                .build();

        String json = mapper.writeValueAsString(request);
        // expected
        mockMvc.perform(MockMvcRequestBuilders.post("/posts")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(json)
                )
                .andExpect(MockMvcResultMatchers.status().isBadRequest())
                .andExpect(MockMvcResultMatchers.jsonPath("$.code").value("400"))
                .andExpect(MockMvcResultMatchers.jsonPath("$.message").value("잘못된 요청입니다."))
                .andExpect(MockMvcResultMatchers.jsonPath("$.validation.title").value(environment.getProperty("post.NotBlank")))
                .andDo(print());
    }


    @Test
    @DisplayName("/posts 요청시 db에 값이 저장된다.")
    void test3() throws Exception {

        // given
        PostCreate request = PostCreate.builder()
                .title("제목입니다.")
                .content("내용입니다.")
                .build();

        String json = mapper.writeValueAsString(request);
        // expected
        mockMvc.perform(MockMvcRequestBuilders.post("/posts")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(json)
                )
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andDo(print());

        // then
        assertEquals(1L, postRepository.count());

        Post post = postRepository.findAll().get(0);
        assertEquals("제목입니다.",post.getTitle());
        assertEquals("내용입니다.",post.getContent());
    }

    @Test
    @DisplayName("글 1개 조회")
    void test4() throws Exception {
        // given
        Post post = Post.builder()
                .title("123456789012345")
                .content("bar")
                .build();
        postRepository.save(post);
        // when

        // expected
        mockMvc.perform(MockMvcRequestBuilders.get("/posts/{postId}",post.getId())
                        .contentType(MediaType.APPLICATION_JSON))
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(post.getId()))
                .andExpect(MockMvcResultMatchers.jsonPath("$.title").value("1234567890"))
                .andExpect(MockMvcResultMatchers.jsonPath("$.content").value("bar"))
                .andDo(print());

        // then
    }


    @Test
    @DisplayName("글 여러개 조회")
    void test5() throws Exception {
        // given

        List<Post> requestPosts = IntStream.range(1,31)
                .mapToObj(i ->
                        Post.builder()
                                .title("title " + i)
                                .content("content " + i)
                                .build()
                ).collect(Collectors.toList());
        postRepository.saveAll(requestPosts);

        // expected
        mockMvc.perform(MockMvcRequestBuilders.get("/posts?page=1&sort=id,desc")
                        .contentType(MediaType.APPLICATION_JSON))
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andExpect(MockMvcResultMatchers.jsonPath("$.length()",Matchers.is(5)))
                .andExpect(MockMvcResultMatchers.jsonPath("$[0].id").value(30))
                .andExpect(MockMvcResultMatchers.jsonPath("$[0].title").value("title 30"))
                .andExpect(MockMvcResultMatchers.jsonPath("$[0].content").value("content 30"))
                .andDo(print());
    }
}

안녕하세요 호돌맨님 질문이 있습니다.

test5를 단독으로 실행하면 문제없는데

전체를 실행했을 때는 postRepository.saveAll 전까지는 requestPosts 안에 Post가 id가 1부터 시작하는데

saveAll을 지나고 나서는 id가 4부터 시작하게됩니다.

@BeforeEach에서 postRepository.deleteAll을 수행하고 있습니다.

 

제생각에는

이게 Entity 의 @GeneratedValue(strategy = GenerationType.IDENTITY) 와 연관이 있는건가요?

해당 설정을 하면 말씀해주신것처럼 persist가 호출되는 시점에 id값을 db로부터 얻어오기 때문에 아무리 row가 지워졌어도 h2 내부적으로 id를1씩 증가시켜왔기에 그 증가된 값이 requestPosts 의 값도 변형시킨것이 맞나요?

 

답변 4

5

호돌맨님의 프로필 이미지
호돌맨
지식공유자

안녕하세요? 호돌맨입니다.

("requestPosts 안에 Post가 id가 1부터 시작하는데" 이 부분은 제가 이해하지 못했습니다. 작성하신 소스를 보면 requestsPosts의 Post데이터는 아직 id값 빌더를 통해 할당하지 않으셨기 때문에 Long 타입이라면 null이 들어가 있을것 같습니다.)

우선은 말씀하신 게 대체로 맞습니다. 정확히 @GeneratedValue(strategy = GenerationType.IDENTITY)에 직접적으로 연관이 있다기 보다도

auto increment

h2, mysql 기준으로 테이블 row를 삭제(postRepository.delete)한다고 해서 id(primary_key)가 1로 초기화 되지는 않습니다. id가 1로 초기화 되는 아래와 같습니다.

  1. 테이블이 삭제 되거나

  2. 테이블이 TRUNCATE 되거나

  3. ALTER TABLE 명령어로 auto increment값을 1로 수정하거나

그러면 어뜨케 할까요?

.andExpect(MockMvcResultMatchers.jsonPath("$[0].id").value(30))

위와같이 코드를 적더라도 id가 30이라고 보장 받을 수 없습니다.
왜냐하면 테스트가 실행되는 순서를 보장할 수 없기 때문입니다.
전체 테스트 실행시 위의 코드를 포함하는 테스트 메서드는 첫 빠따로 수행될수도 있고 마지막으로 수행될수도 있습니다.
그렇기 때문에 아래와같이 '요청한 데이터 의 id값인 requestsPosts.get(마지막index).id로 체크하는 게 좋아보입니다.

.andExpect(MockMvcResultMatchers.jsonPath("$[0].id").value(request.Posts.get(29인가 30인가).getId()))

감사합니다.

임도현님의 프로필 이미지
임도현
질문자

그렇군요 null이 들어가겠군요 제가 잘못봤습니다

빠른 답변 너무 감사합니다!!!!!!!!!!!

0

좋은 질문, 좋은 답변 감사합니다 !

0

새벽 1시까지 삽질하다가,, 발견해서 해결하고 잡니다. 감사합니다.!

0

저도 이걸로 오늘 하루종일 삽질했는데 감사합니다,,,