본문 바로가기

Spring 공부

spring 공부 - 테스트코드

728x90
반응형

 

테스트코드

 

작성한 코드가 의도대로 잘 동작하고 예상치 못한 문제가 없는지 확인할 목적으로 작성하는 코드

 

given-when-then 패턴

 

테스트 코드를 세 단계로 구분해 작성하는 방식

 

given : 테스트 실행을 준비하는 단계
when : 테스트를 진행하는 단계
then : 테스트 결과를 검증하는 단계

 

@DisplayName("새로운 메뉴를 저장한다.")
@Test
public void saveMenuTest(){
	// given : 메뉴를 저장하기 위한 준비 과정
    final String name = "아메리카노";
    final int price = 2000;
    
    final Menu americano = new Menu(name, price);
    
    // when : 실제로 메뉴를 저장
   	final long saveId = menuService.save(americano);
    
    // then : 메뉴가 잘 추가되었는지 검증
    final Menu savedMenu = menuService.findById(saveId).get();
    assertThat(savedMenu.getName()).isEqualTo(name);
    assertThat(savedMenu.getPrice()).isEqualTo(price);
}

 

DisplayName("새로운 메뉴를 저장한다."): 이 어노테이션은 해당 테스트 메소드의 표시 이름을 설정. 테스트 결과 보고서에 표시.

 

@Test: 이 어노테이션은 JUnit에서 해당 메소드가 테스트 메소드임을 나타낸다.

 

final String name = "아메리카노";, final int price = 2000;: 테스트를 위해 저장할 메뉴의 이름과 가격을 설정.

 

final Menu americano = new Menu(name, price);: 주어진 이름과 가격으로 새로운 메뉴 객체를 생성.

 

final long saveId = menuService.save(americano);: 생성한 메뉴를 저장하고, 저장된 메뉴의 ID를 반환.

 

final Menu savedMenu = menuService.findById(saveId).get();: 저장된 메뉴를 조회. findById() 메소드를 사용하여 저장된 메뉴의 ID를 기반으로 조회하며, Optional을 반환하므로 .get()을 통해 실제 메뉴 객체를 가져온다.

 

assertThat(savedMenu.getName()).isEqualTo(name);, assertThat(savedMenu.getPrice()).isEqualTo(price);: 저장된 메뉴의 이름과 가격이 기대한 값과 같은지 검증. assertThat()과 isEqualTo()는 AssertJ 라이브러리를 사용하여 객체의 상태를 검증하는데 사용.

 

 

JUnit

 

자바 언어를 위한 단위 테스트 프레임워크
단위 테스트: 작성한 코드가 의도대로 작동하는지 작은 단위로 검증하는 것

 

테스트 방식을 구분할 수 있는 애너테이션 제공
@Test 애너테이션으로 메서드 호출할 때마다 새 인스턴스 생성, 독립 테스트 가능
예상 결과를 검증하는 어설션 메서드 제공
사용 방법이 단순, 테스트 코드 작성 시간이 적음
자동 실행, 자체 결과를 확인하고 즉각적인 피드백 제공

 

JUnit 애너테이션

 

@BeforeAll
전체 테스트를 시작하기 전에 처음으로 한 번만 실행 , 예를 들어 데이터베이스 연결해야하거나 테스트 환경을 초기화 할때 사용
테스트 실행주기에서 한 번 만 호출되어야 하기 때문에 메서드를 static으로 선언

 

@BeforeEach
테스트 케이스 시작하기 전에 매번 실행, 메서드에서 사용하는 객체를 초기화하거나 테스트에 필요한 값을 미리 넣을 때 사용
각 인스턴스에 대해 메서드 호출해야하므로 static X 아님

 

@AfterAll
전체 테스트 마치고 종료하기 전에 한 번만 실행, 데이터 베이스 연결을 종료할 때나 공통적으로 사용하는 자원 해제할 때 사용
한 번만 호출되므로 static

 

@AfterEach
각 테스트 케이스를 종료하기 전 매번 실행, 특정 데이터를 삭제해야 하는 경우 사용, static X 아님

 

 

@BeforeAll 설정한 메서드 실행되고
@BeforeEach -> @Test -> @AfterEach 생명주기로 테스트 실행
@AfterAll 실행하고 종료된다.

 

 

AssertJ

 

JUnit과 함께 사용해 검증문의 가독성을 높여주는 라이브러리

 

Assertions.assertEquals(sum, a+b);

 

↓ 가독성이 더 좋음

AssertThat(a + b).isEqualTo(sum);

 

 

isEqualTo(A) : A 값과 같은지 검증
isNotEqualTo(A) : A 값과 다른지 검증
contains(A) : A 값을 포함하는지 검증
doesNotContain(A) : A 값을 포함하지 않는지 검증
startsWith(A) : 접두사가 A인지 검증
endsWith(A) : 접미사가 A인지 검증
isEmpty() : 비어 있는 값인지 검증
isNotEmpty() : 비어 있지 않은 값인지 검증
isPositive() : 양수인지 검증
isNegative() : 음수인지 검증
isGreaterThan(1) : 1보다 큰 값인지 검증
isLessThan(1) : 1보다 작은 값인지 검증

@SpringBootTest
@AutoConfigureMockMvc
class TestControllerTest {

  @Autowired
  protected MockMvc mockMvc;

  @Autowired
  private WebApplicationContext context;

  @Autowired
  private MemberRepository memberRepository;

  @BeforeEach
  public void mockMvcSetUp() {
    this.mockMvc = MockMvcBuilders.webAppContextSetup(context)
            .build();
  }

  @AfterEach
  public void cleanUp() {
    memberRepository.deleteAll();
  }
}

 

@SpringBootTest
메인 애플리케이션 클래스에 추가하는 에너테이션인 @SpringBootApplication이 있는 클래스를 찾는다. 그 클래스에 포함되어 있는 빈을 찾은 다음 테스트용 애플리케이션 컨텍스트라를 만듦

 

@AutoConfigureMockMvc
MockMvc를 생성하고 자동으로 구성하는 애너테이션
MockMvc는 애플리케이션을 서버에 배포하지 않고도 테스트용 MVC 환경을 만들어 요청, 전송, 응답 제공하는 유틸리티 클래스
컨트롤러를 테스트할때 사용하는 클래스

 

@BeforeEach
MockMvcSetUp() 메서드를 실행해 MockMvc 설정

 

@AfterEach
cleanUp() 메서드 실행해 member 테이블에 있는 데이터들을 모두 삭제

 

 @DisplayName("getAllMembers: 아티클 조회에 성공한다.")
  @Test
  public void getAllMembers() throws Exception {
    // given  // 멤버를 저장한다.
    final String url = "/test";
    Member savedMember = memberRepository.save(new Member(1L, "홍길동"));

    // when  // 멤버 리스트를 조회하는 API 호출
    final ResultActions result = mockMvc.perform(get(url) // 1
            .accept(MediaType.APPLICATION_JSON)); // 2

    // then  // 응답 코드가 200 OK이고, 반환받은 값 중에 0번째 요소의 id와 name이 저장된 값과 같은지 확인
    result
            .andExpect(status().isOk())
            .andExpect(jsonPath("$[0].id").value(savedMember.getId()))
            .andExpect(jsonPath("$[0].name").value(savedMember.getName()));
  }

 

@DisplayName("getAllMembers: 아티클 조회에 성공한다."): 이 어노테이션은 해당 테스트 메소드의 표시 이름을 설정. 테스트 결과 보고서에 표시.

 

@Test: 이 어노테이션은 JUnit에서 해당 메소드가 테스트 메소드임.

 

final String url = "/test";: 테스트할 API의 URL을 설정

 

Member savedMember = memberRepository.save(new Member(1L, "홍길동"));: 테스트를 위해 멤버를 저장. 여기서는 아이디가 1이고 이름이 "홍길동"인 멤버를 저장한다.

 

final ResultActions result = mockMvc.perform(get(url) // 1 .accept(MediaType.APPLICATION_JSON));: 설정된 URL에 GET 요청을 보내고, 반환되는 ResultActions 객체를 얻는다. accept(MediaType.APPLICATION_JSON)은 요청이 JSON 형식의 응답을 기대함.

 

result.andExpect(status().isOk()): 응답의 상태 코드가 200 OK 검증.

 

result.andExpect(jsonPath("$[0].id").value(savedMember.getId())): 반환된 JSON 응답에서 첫 번째 요소의 id가 저장된 멤버의 id와 같은지를 검증. jsonPath("$[0].id")는 JSON 응답의 첫 번째 요소의 id를 나타낸다.

 

result.andExpect(jsonPath("$[0].name").value(savedMember.getName())): 반환된 JSON 응답에서 첫 번째 요소의 name이 저장된 멤버의 name과 같은지를 검증한다. jsonPath("$[0].name")는 JSON 응답의 첫 번째 요소의 name을 나타낸다.

 

HTTP 주요 응답 코드
코드 매핑메소드 설명
200 OK : isOk() - 200 OK인지 검증
201 Created : isCreated() - 201 Created인지 검증
400 Bad Request : isBadRequest() - 400 Bad Request인지 검증
403 Forbidden : isForbidden() - 403 Forbidden인지 검증
404 Not Found : isNotFound() - 404 NotFound인지 검증
400 번대 응답코드 : is4xxClientError() - 400 번대 응답코드인지 검증
500 Internal Server Error : isInternalServerError()- 500 Internal Server Error인지 검증
500 번대 응답코드 : is5xxServerError()- 500번대 응답코드인지 검증

반응형