본문 바로가기
Backend/<스프링 부트 3 백엔드 개발자 되기>

04장 스프링 부트 3와 테스트

by ccooll 2023. 10. 31.

4.1 테스트 코드 개념 익히기

1. 테스트 코드란?

test 디렉토리에서 작업

 

- given-when-then 패턴

1. given : 테스트 실행을 준비하는 단계

2. when : 테스트를 진행하는 단계

3. then : 테스트 결과를 검증하는 단계

 

 

4.2 스프링 부트 3와 테스트

1. JUnit?

: 자바 언어를 위한 단위 테스트 프레임워크

※ 단위 테스트 : 작성한 코드가 의도대로 작동하는지 작은 단위로 검증하는 것을 의미함. 이때 단위는 보통 메서드

 

** JUnit의 특징 **

더보기

- 테스트 방식을 구분할 수 있는 애너테이션을 제공

- @Test 애너테이션으로 메서드를 호출할 때마다 새 인스턴스를 생성, 독립 테스트 가능

- 예상 결과를 검증하는 어설션 메서드 제공

- 사용 방법이 단순, 테스트 코드 작성 시간이 적음

- 자동 실행, 자체 결과를 확인하고 즉각적인 피드백을 제공

 

- JUnit으로 단위 테스트 코드 만들기

1. src/test/java/JUnitTest.java

public class JUnitTest {

    @DisplayName("1 + 2는 3이다")
    @Test
    public void junitTest() {
        int a = 1;
        int b = 2;
        int sum = 3;
	
    	// 값이 같은지 확인
        Assertions.assertEquals(a + b, sum);
    }
}

- @DisplayName 애너테이션은 테스트 이름 명시

- @Test 애너테이션을 붙인 메서드는 테스트를 수행하는 메서드가 됨

- JUnit은 테스트끼리 영향을 주지 않도록 각 테스트를 실행할 때마다 테스트를 위한 실행 객체를 만들고 테스트가 종료되면 실행 객체를 삭제함

- junitTest() 메서드에 작성한 테스트 코드

: JUnit에서 제공하는 검증 메서드인 assertEquals()로 a+b와 sum의 값이 같은지 확인

※ assertEquals(기대하는 값, 실제로 검증할 값)

 

2. 테스트 실행

 

3. 테스트 실패할 경우

: JUnit은 테스트 케이스가 하나라도 실패하면 전체 테스트를 실패한 것으로 보여줌

 

4. JUnit의 애너테이션 알아보기

- src/test/java/JUnitCycleTest.java 

public class JUnitCycleTest {

    @BeforeAll	// 전체 테스트를 시작하기 전에 1회 실행 → 메서드는 static으로 선언
    static void beforeAll() {
        System.out.println("@BeforeAll");
    }

    @BeforeEach	// 테스트 케이스를 시작하기 전마다 실행
    public void beforeEach() {
        System.out.println("@BeforeEach");
    }

    @Test
    public void test1() {
        System.out.println("test1");
    }

    @Test
    public void test2() {
        System.out.println("test2");
    }

    @Test
    public void test3() {
        System.out.println("test3");
    }

    @AfterAll	// 전체 테스트를 마치고 종료하기 전에 1회 실행 → 메서드는 static으로 선언
    static void afterAll() {
        System.out.println("@AfterAll");
    }

    @AfterEach	// 테스트 케이스를 종료하기 전마다 실행
    public void afterEach() {
        System.out.println("@AfterEach");
    }

}

- @BeforeAll 애너테이션

: 전체 테스트를 시작하기 전에 처음으로 한 번만 실행함. 전체 테스트 실행 주기에서 한 번만 호출되어야 하기 때문에 메서드를 static으로 선언

ex) 데이터베이스를 연결해야하거나 테스트 환경을 초기화할 때 사용됨

 

- @BeforeEach 애너테이션

: 테스트 케이스를 시작하기 전에 매번 실행됨. 각 인스턴트에 대해 메서드를 호출해야 하므로 메서드는 static이 아니어야 함(위 코드의 경우 public)

ex) 테스트 메서드에서 사용하는 객체를 초기화하거나 테스트에 필요한 값을 미리 넣을 때 사용

 

- @AfterAll 애너테이션

: 전체 테스트를 마치고 종료하기 전에 한 번만 실행됨. 전체 테스트 실행 주기에서 한 번만 호출되어야 하므로 메서드를  static으로 선언해야 함

ex) 테이터베이스 연결을 종료할 때나 공통적으로 사용하는 자원을 해제할 때 사용

 

- @AfterEach 애너테이션

: 각 테스트 케이스를 종료하기 전 매번 실행함. 메서드는 static이 아니어야 함

ex) 테스트 이후에 특정 데이터를 삭제해야 하는 경우 사용

 

 

@BeforeAll → @BeforeEach → @Test → @AfterEach → @AfterAll

 

 

 

5. 테스트 코드 실행 결과 살펴보기, AssertJ

- AssertJ로 검증문 가독성 높이기

 

// 기댓값과 비교값이 잘 구분이 되지 않는 Assertion

Assertions.assertEquals(a + b, sum);

 

// 가독성이 좋은 AssertJ

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

a와 b를 더한 값sum과 같아야 한다

 

 

 

4.3 제대로 테스트 코드 작성해보기

1. test/java/me/cool/TestControllerTest.java

 

2.

@SpringBootTest		// 테스트용 애플리케이션 컨텍스트 생성
@AutoConfigureMockMvc	// MockMvc 생성
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 테이블에 있는 데이터들을 모두 삭제해 줌

 

 

3. TestController의 로직을 테스트하는 코드 작성

test/java/me/cool/TestControllerTest.java

- Given-When-Then 패턴 적용

 Given : 멤버를 저장함

 When : 멤버 리스트를 조회하는 API 호출

 Then : 응답 코드가 200 OK이고, 반환받은 값 중에 0번째 요소의 id와 name이 저장된 값과 같은지 확인

@SpringBootTest
@AutoConfigureMockMvc
class TestControllerTest {

	// 생략

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

        // when
        final ResultActions result = mockMvc.perform(get(url) // 1
                .accept(MediaType.APPLICATION_JSON)); // 2

        // then
        result
                .andExpect(status().isOk())
                .andExpect(jsonPath("$[0].id").value(savedMember.getId()))
                .andExpect(jsonPath("$[0].name").value(savedMember.getName()));
    }
}

 

 

 

// when
final ResultActions result = mockMvc.perform(get(url)
		.accept(MediaType.APPLICATION_JSON));

perform() 메서드는 요청을 전송하는 역할을 하는 메서드

  결과로 ResultActions 객체를 받으며, ResultActions 객체는 반환값을 검증하고 확인하는 andExpect() 메서드를 제공해줌

 

② accept() 메서드는 요청을 보낼 때 무슨 타입으로 응답을 받을지 결정하는 메서드

  JSON, XML 등 다양한 타입이 있지만, 여기에서는 JSON을 받음

 

 

// then
result
        .andExpect(status().isOk())
        .andExpect(jsonPath("$[0].id").value(savedMember.getId()))
        .andExpect(jsonPath("$[0].name").value(savedMember.getName()));

③ andExpect() 메서드는 응답을 검증함. TestController에서 만든 API는 응답으로 OK(200)을 반환하므로 이에 해당하는 메서드인 isOk를 사용해 응답 코드가 OK(200)인지 확인함

 

④ jsonPath("$[0].${필드명}")JSON 응답값의 값을 가져오는 역할을 하는 메서드

   0번째 배열에 들어있는 객체의 id, name값을 가져오고, 저장된 값과 같은지 확인함

 

 

4. 테스트 실행

 

 

 

** 핵심 요약 **

더보기

1. 테스트 코드를 작성하면 코드의 기능이 제대로 작동한다는 것을 검증할 수 있다. 테스트 코드는 보통 테스트를 준비하는 given, 테스트를 실제로 진행하는 when, 테스트 결과를 검증하는 then으로 구분된다.

 

2. JUnit은 단위 테스트를 할 때 사용하는 자바 테스트 프레임워크이다. @BeforeAll 애너테이션으로 설정한 메서드가 실행되고, 그 이후에는 테스트 케이스 개수만큼 @BeforeEach → @Test → @AfterEach의 생명주기를 가지고 실행한다. 모든 테스트가 완료되면 마지막으로 @AfterAll 애너테이션으로 설정한 메서드가 실행되고 종료된다.

 

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