Search
Duplicate
🔫

하나의 테스트에서 PK 증가로 인해 Assertion 실패하는 문제

분야
주제
심각도
낮음🤒
제보자
담당자
작성자
상태
처리 완료
이슈링크(optional)
작성일자
2023/08/29 10:16
공개여부
비공개
글감

겪은 문제

Nested Class로 Test를 진행할 때, Create하는 경우에 비록 해당 테스트 시나리오에서는 매 test마다 DB에 하나씩만 얹어지지만, 시나리오가 유지되므로 PK가 증가하였고, Assertion에서 기대했던 1L이 아닌 2L로 해야만 테스트가 통과되는 문제가 있었다.

재현 방법

@Nested @DisplayName("POST /v1/members") class CreateMember { private final String url = "/v1/members"; @BeforeEach void setup() { given(memberImageManager.uploadMemberProfileImage(any())).willReturn(randomString()); } @Test @DisplayName("42 OAuth 사용자는 회원 가입을 할 수 있다.") void createMember() throws Exception { Member noneRegisteredMember = TestMember.builder() .oauthId("131541") .oauthType(OauthType.FORTY_TWO) .oauthName("sanan") .memberRole(MemberRole.NOT_REGISTERED) .build().asMockEntity(1L); String token = stubToken(noneRegisteredMember, now, 1); System.out.println("token = " + token); MockMultipartFile imageFile = new MockMultipartFile("imageData", "test.jpg", "image/jpeg", "test".getBytes()); MockHttpServletRequestBuilder req = multipart(url) .file(imageFile) .cookie(new Cookie("access_token", token)) .param("memberName", "sanan") .param("statement", "안녕하세요?") .param("categoryFilters", animalCategories.get(0).getCategoryName()) .header(AUTHORIZATION, BEARER + token); mockMvc.perform(req) .andDo(print()) .andExpect(status().isOk()) .andDo(result -> { Member member = em.find(Member.class, noneRegisteredMember.getId()); assertThat(member.getMemberRole()).isEqualTo(MemberRole.USER); assertThat(member.getOauthProfile().getId()).isEqualTo(noneRegisteredMember.getOauthProfile().getId()); assertThat(member.getOauthProfile().getName()).isEqualTo(noneRegisteredMember.getOauthProfile().getName()); assertThat(member.getOauthProfile().getType()).isEqualTo(noneRegisteredMember.getOauthProfile().getType()); assertThat(member.getNickname()).isEqualTo("sanan"); assertThat(member.getStatement()).isEqualTo("안녕하세요?"); }); } @DisplayName("프로필 이미지를 업로드하지 않으면 null로 입력된다.") @Test void createMember2() throws Exception { Member noneRegisteredMember = TestMember.builder() .oauthName("sanan") .oauthId("sadfasdf") .oauthType(OauthType.FORTY_TWO) .nickname("sanan") .memberRole(MemberRole.NOT_REGISTERED) .build().asMockEntity(1L); String token = stubToken(noneRegisteredMember, now, 1); MockHttpServletRequestBuilder req = multipart(url) .cookie(new Cookie("access_token", token)) .param("memberName", "sanan") .param("statement", "안녕하세요?") .param("categoryFilters", animalCategories.get(0).getCategoryName()) .header(AUTHORIZATION, BEARER + token); mockMvc.perform(req) .andDo(print()) .andExpect(status().isOk()) .andDo(e -> { Member member = em.find(Member.class, noneRegisteredMember.getId()); assertThat(member.getMemberRole()).isEqualTo(MemberRole.USER); assertThat(member.getOauthProfile().getId()).isEqualTo(noneRegisteredMember.getOauthProfile().getId()); assertThat(member.getOauthProfile().getName()).isEqualTo(noneRegisteredMember.getOauthProfile().getName()); assertThat(member.getOauthProfile().getType()).isEqualTo(noneRegisteredMember.getOauthProfile().getType()); assertThat(member.getNickname()).isEqualTo("sanan"); assertThat(member.getStatement()).isEqualTo("안녕하세요?"); assertThat(member.getProfileImageUrl()).isNull(); }); } }
Java
복사

시도한 방법

2L로 테스트를 성공하게 변경하기
이 방법은 당시에는 테스트가 통과할 수 있으나, 테스트 자체가 순서가 보장되어 있지 않고, 오히려 이를 위해 테스트의 순서를 정하는 것 또한 내키지 않았다.
Table의 모든 Data Delete하기
맨 처음에는 @Transactional에도 불구하고 기존의 Data가 남아있어서 2L로 밀리는가 싶어서 BeforeEach로 해당 Table에 있는 데이터들을 DELETE하는 쿼리를 실행했었는데 동일한 문제를 겪었다.

해결법

em.createNativeQuery("ALTER TABLE member ALTER COLUMN id RESTART WITH 1").executeUpdate();
Java
복사
결국 매 테스트마다 해당 Table의 PK 전략, 특히 우리의 경우 auto-increment를 사용 중이었는데, 이 값을 초기화하여 해결했다.