Testing6 테스트 코드 뜯어보기 - 조연들을 한자리에 테스트 코드 관련 시리즈 글을 따라오며 계속 곁을 스쳤지만 정면으로 다루지 못한 것들이 있다. 여러 확장을 조합하는 @ExtendWith, 테스트를 계층으로 묶는 @Nested, 목에 넘어간 인자를 사후에 붙잡는 ArgumentCaptor, 가독성 레이어인 BDDMockito, 그리고 죽은 스텁을 실패로 노출시키는 Strict Stubbing. 이번 시리즈 마지막 글에서 이 조연들을 한자리에 모았다.Intro@ExtendWith는 JUnit4의 @RunWith(하나만)를 여러 개 조합 가능한 Extension 모델로 대체한 것. before는 선언 순서, after는 역순으로 도는 양파 구조다.@Nested는 테스트를 "대상 메서드 > 시나리오" 계층으로 묶는다. non-static inner class.. 2026. 7. 7. 테스트 코드 뜯어보기 - @ParameterizedTest는 for문의 문법 설탕이 아니다 "같은 로직을 값만 바꿔 여러 번 돌린다"는 점만 보면 @ParameterizedTest는 for문과 비슷해 보인다. 그런데 실패가 났을 때 완전히 다르게 행동한다. 이 차이(실패 격리)와, 그걸 가능하게 하는 ArgumentsProvider SPI, 그리고 enum 상태 전이 검증에 이걸 어떻게 응용할지를 정리했다.Intro@ValueSource, @CsvSource, @MethodSource, @EnumSource는 전부 ArgumentsProvider SPI를 트리거하는 메타 애노테이션이다.@ParameterizedTest가 데이터 N개를 받으면 JUnit은 이를 N개의 독립 invocation으로 취급한다.for문은 첫 실패에서 즉시 중단돼 뒤 케이스가 검증 안 되지만, @Parameterized.. 2026. 7. 7. 테스트 코드 뜯어보기 - MockMvc는 서블릿 컨테이너를 흉내 내는가 @AutoConfigureMockMvc(addFilters = false). 이 한 줄이 무엇을 끄는지, 그리고 인증 필터를 꺼버린 자리를 왜 ThreadLocal을 직접 세팅해서 메우는지를 정리했다. 여기엔 "MockMvc가 진짜 HTTP를 날리는가"라는 오래된 오해와, ThreadLocal 누수라는 flaky 테스트의 단골 원인이 함께 얽혀 있다.IntroMockMvc는 실제 서블릿 컨테이너를 띄우지 않는다. 가짜 서블릿 API를 만들어 진짜 DispatcherServlet에 직접 넘긴다. 요청 매핑부터 @Valid, @ExceptionHandler까지 프로덕션과 같은 파이프라인이 돈다.addFilters = false는 컨텍스트의 Filter 빈들을 MockMvc 체인에 등록하지 않는다. 즉 인증 .. 2026. 7. 5. 테스트 코드 뜯어보기 - @WebMvcTest만 붙였더니 500이 났다 컨트롤러 슬라이스 테스트를 짜다가 만난 황당한 상황. @WebMvcTest를 정석대로 붙였는데 404도 아니고 500이 돌아왔다. 범인은 우리 앱의 scanBasePackages 설정이었고, 해결책은 @Import였다. 이게 왜 우리 레포에선 사실상 필수가 되는지 백그라운드까지 파봤다.Intro@WebMvcTest는 전체 컨텍스트 대신 MVC 계층만 가볍게 띄우는 테스트 슬라이스다.슬라이스는 명시적 설정이 없으면 위로 올라가며 @SpringBootApplication 클래스를 찾아 "주 설정"으로 재사용한다.우리 앱은 @SpringBootApplication(scanBasePackages = "com.acme.app.config")로 스캔 범위를 config 패키지로 좁혀놨다.그래서 슬라이스의 컴포넌트 .. 2026. 7. 5. 테스트 코드 뜯어보기 - @Mock, @MockBean, @InjectMocks는 같은 목이 아니다 두 테스트 파일을 나란히 놓고 보면 겉보기엔 둘 다 "목을 쓰는 단위 테스트"다. 그런데 하나는 @Mock+@InjectMocks, 다른 하나는 @MockBean을 쓴다. 왜 다를까. 목 객체를 만드는 라이브러리는 같은 Mockito인데, 그 목을 어디에 등록하고 어떻게 주입하는지는 완전히 다른 세계라는 걸 정리했다.Intro@Mock+@InjectMocks는 ApplicationContext가 아예 없다. Mockito가 리플렉션으로 손수 조립하는 순수 JVM 객체 그래프다.@MockBean은 Spring 컨텍스트가 실제로 뜬 상태에서 그 안의 빈을 목으로 치환한다. 주입도 Spring의 정상 DI 절차 안에서 일어난다.@Autowired는 "무엇으로 채울지"가 아니라 "채워진 컨테이너에서 값을 꺼내오.. 2026. 7. 5. 테스트 코드 뜯어보기 - LocalDateTime.now()는 왜 테스트를 괴롭히는가 우리 API 서버의 테스트 코드를 하나하나 뜯어보며 "이 애노테이션이 백그라운드에서 정확히 무슨 일을 하는가"를 정리한 시리즈다. 첫 글은 시간이다. 서비스 코드가 LocalDateTime.now()를 직접 부르는 순간 테스트가 어떻게 무너지는지, 그리고 우리 팀이 그걸 두 가지 전략으로 어떻게 나눠서 다루는지 적었다.IntroLocalDateTime.now()는 매 실행마다 다른 값이라 테스트가 isEqualTo로 정확히 단언할 방법이 없다.근본 해법은 Clock을 주입받아 LocalDateTime.now(clock)을 쓰는 것. 테스트에선 Clock.fixed(...)로 시간을 얼려서 결정론적으로 만든다.하지만 우리 코드베이스엔 now() 직접 호출이 65개 넘는 파일에 퍼져 있어서, 전부 소급 리팩.. 2026. 7. 5. 이전 1 다음