테스트 코드 정리(25.3.7.금)

kinkin_a·2025년 3월 7일

내일배움캠프 TIL

목록 보기
70/100

💻 1.테스트코드란?


  • 프로그램의 유지보수를 위해 테스트용으로 개발한 코드
  • 테스트코드를 작성하지 않은 프로그램과의 차이는 시간이 지날수록 차이가 극명해진다.
  • given-when-then 의 구조로 이뤄졌고, 개발자가 메소드의 작동여부를 증명하기 위해 간단한 시나리오를 짠다고 생각하면 된다.
    • given(준비): 테스트를 위한 환경을 세팅하는 단계(ex) 의존성 주입, 가짜객체 설정 등)
    • when(실행): 테스트 할 메소드를 실행하는 단계며, 주어진 입력으로 메소드를 호출한다.(ex) given(repository.method()).willReturn();
    • then(검증): 결과를 확인하고 검증한다. 예상결과값을 설정해서 비교하거나 호출여부를 확인한다.
  • 테스트 커버리지: 전체 코드 중 테스트에 성공한 비율을 보여준다. 100%는 완벽하지만, 방대한 양의 프로그램에선 거의 불가능하다고 보면 된다.
  • 프로그램을 기능별로 Controller - Service- Repository 로 나눠 의존성 주입으로 구현하는 이유 중 하나도 테스트 코드를 용이하게 검증하기 위해서다.


📦 2. Mock(가짜 객체)는 무엇인가?


  • 외부 데이터 저장소를 테스트 목적으로 불러오기엔 양이 너무 방대해서 테스트가 무거워져서 느려진다. 그래서 가짜 객체를 만들어, DB나 API에 갈 필요도 없이 가짜 객체로 설정해 외부 의존성을 없애고 테스트에 집중하도록 한다.
  • 주로 외부 시스템까지 불러오는 것을 막아 테스트 코드 실행 속도를 빠르게 한다. 하지만 가짜 객체의 지나친 남용은 테스트코드 가독성과 본질을 해친다.(ex) repository)
  • 주 테스트 대상은 @InjectMock, 그 외는 @Mock을 붙인다.
  • 다만, 가짜 객체는 생성자를 호출하지 않기 때문에 값을 호출해도 null이나 0이 뜬다. 이를 해결하기 위해서 given().willReturn() 으로 원하는 값을 임의로 지정해 테스트 검증에 지장이 없도록 한다. (stubbing)
  • 혹은 spy를 이용해 가짜객체를 필요한 부분만 잠시 실객체로 변환시켜 해당 메소드가 제대로 동작하는지 검사한다.


⭕️ 3. any() 는 무엇인가?


  • any는 가짜객체 메소드를 호출할 때 입력하는 매개변수 대체용도이다.
  • any(), anyLong(), anyInt(), anyString()이 있다.
  • 주로 given(repository.method(any()).willReturn(); 식으로 쓰인다.
  • 메소드가 호출됨을 확인하는 것이 목적이므로 실제 매개변수는 중요하지 않을 때 쓰인다.
  • any로 값의 범위에 제한을 두지 않기 때문에, 유연하고 안정성 있는 테스트 코드를 구현할 수 있다.
  • 실제 값을 검증하는 부분인 when- then에서는 자중하는 것이 좋음!



📸 4.spy()는 어떤 용도?


  • 실제 객체를 감싸서 일부만 조작할 수 있도록 하는 가짜 객체(Mock)
  • 가짜객체만으로는 로직을 검증하기에 한계가 있으므로, Mock을 잠시 실제객체로 변환함.
  • return값을 개발자가 임의로 지정해줘야하는 Mock과 달리, spy는 실제로 동작해 생성자나 매개변수로 주어진 값에 따라 return값을 준다.
  • 주로 테스트 대상 메소드가 실제로 호출되는지 감시하는 용도로 쓰인다.



✅ 5. 테스트 코드에 필요한 메소드 정리


JUnit + Mockito + Spring Boot

구분메서드 / 어노테이션설명
JUnit 검증 메서드assertEquals(a, b)두 값이 같은지 검증
assertNotEquals(a, b)두 값이 다르면 테스트 통과
assertTrue(condition)조건이 true인지 확인
assertFalse(condition)조건이 false인지 확인
assertNull(object)객체가 null인지 확인
assertNotNull(object)객체가 null이 아닌지 확인
assertArrayEquals(arr1, arr2)배열이 같은지 확인
assertIterableEquals(list1, list2)리스트가 같은지 확인
assertThrows(Exception.class, () -> {...})특정 예외 발생 여부 확인
assertTimeout(Duration.ofMillis(100), () -> {...})코드가 100ms 내 실행되는지 확인
JUnit 테스트 어노테이션@BeforeEach각 테스트 전에 실행 (초기화)
@AfterEach각 테스트 후 실행 (정리)
@BeforeAll모든 테스트 실행 전에 한 번 실행 (static 필요)
@AfterAll모든 테스트 실행 후 한 번 실행 (static 필요)
Mockito (Mock & Spy)mock(Class.class)완전한 가짜 객체 생성
spy(new Object())실제 객체를 감싸서 일부만 가짜로 변경
when(mock.method()).thenReturn(value)특정 메서드 호출 시 가짜 값 반환
doReturn(value).when(spy).method()Spy 객체에서 특정 메서드만 조작
verify(mock, times(n)).method()특정 메서드가 n번 호출되었는지 검증
verify(mock, never()).method()특정 메서드가 한 번도 호출되지 않았는지 검증
Mockito 어노테이션@MockMock 객체 생성
@SpySpy 객체 생성 (실제 동작 유지)
@InjectMocksMock 객체를 주입 (의존성 주입 자동 처리)
@MockBeanSpring 컨텍스트에서 특정 빈을 Mock으로 교체
Spring Boot 테스트 어노테이션@SpringBootTest스프링 부트 통합 테스트 (실제 빈 등록)
@WebMvcTest(Controller.class)Controller만 테스트 (MockMvc 사용)
@DataJpaTestJPA 관련 Repository 테스트 (DB 자동 롤백)
MockMvc API 테스트mockMvc.perform(get("/api"))GET 요청 실행
mockMvc.perform(post("/api").contentType(MediaType.JSON).content("{...}"))POST 요청 실행
mockMvc.perform(delete("/api/1"))DELETE 요청 실행
.andExpect(status().isOk())HTTP 응답 코드가 200인지 검증
.andExpect(jsonPath("$.name").value("testUser"))JSON 응답 값 검증

0개의 댓글