Java에서 테스트 코드 작성하기

junto·2024년 2월 9일
0

spring

목록 보기
4/30
post-thumbnail

테스트

왜 테스트해야 할까?

  • 테스트란 소프트웨어 개발 핵심 과정 중 하나로 코드의 안정성과 기능성 및 성능을 검증하는 데 필수적이다.
  • 테스트를 통해 재배포, 재개발 비용 감소하며 코드 품질이 높아져 유지보수가 더욱 쉬워진다는 장점이 있다.

어떤 테스트를 얼마나 작성하지?

  • 테스트 피라미드는 테스트의 다양한 유형을 정의하여 중요도와 범위를 시각적으로 나타내는 모델이다. 테스트 범위와 속도 등을 고려하여 어떤 테스트를 얼마나 수행해야 하는지 균형을 제시한다.
  • 핵심 원칙은 상단의 테스트는 적게, 하단의 테스트는 많이 작성되어야 한다는 것이다.

1. 단위테스트

  • 단위 테스트는 가장 아래에 위치하며, 가장 작은 단위의 코드를 테스트한다.
  • 독립적으로 빠르게 실행되며 이를 위해 Mock 객체나 Stub을 사용할 수 있다.

2. 서비스 테스트

  • 서비스 테스트는 통합 테스트라고도 하며, 서로 다른 컴포넌트나 시스템들이 함께 잘 작동하는지 확인한다.

3. UI 테스트

  • UI 테스트는 앤드 투 앤드 테스트라고도 하며, 사용자의 관점에서 시스템의 전체 흐름을 검증한다.
  • 전체 테스트 중 가장 적은 수로 이루어지며, 테스트 실행에 가장 긴 시간이 걸린다.

좋은 테스트를 위한 FIRST 원칙

  • Fast: 테스트는 지속적이고 빠른 피드백을 줄 수 있어야 한다.
  • Independent: 테스트들은 서로 독립적이어야 한다.
  • Repeatable: 어떤 환경에서도 테스트는 반복할 수 있어야 한다.
  • Self-validating: 스스로 검증할 수 있어야 한다.
  • Timely: 적절한 시기에 테스트를 작성해야 한다.

테스트 관련 용어

1. 목(Mock) 객체

  • 실제 객체를 흉내 내는 가짜 객체로 주로 단위 테스트에서 사용된다.
  • 다음과 같은 목적을 가진다.
    1. 의존관계 분리: 실제 서비스나 데이터베이스에 의존하는 경우 Mock 객체로 대체하여 테스트 환경 설정의 복잡성을 줄인다.
    2. 상태, 행위 검증: 특정 상태나 특정 상황을 Mock 객체로 쉽게 만들어 모의 테스트를 할 수 있게한다.
    3. 속도: 외부 API나 데이터베이스를 사용할 경우 발생하는 지연 시간을 줄일 수 있다.
  • 예를 들어 테스트 중인 코드가 Mock 객체와 예상대로 상호작용 하는지를 검증한다.

2. 스텁(Stub)

  • 특정 테스트를 위한 고정된 데이터를 제공하며 특정 상황을 모의하는 데 사용된다.
  • 예를 들어 특정한 메서드 호출 시 항상 동일한 값을 반환하도록 설정하는 것이다.

3. 테스트 대역(Test Double)

  • 실제 구현대신 사용되는 객체를 총칭하는 용어이다. Mock, Stub, Dummy, Fake, Spy를 사용함으로써 테스트의 유연성을 높이고 다양한 시나리오를 효과적으로 테스트한다.

3. 더미(Dummy)

  • 객체는 전달되지만 실제로는 사용되지 않는 객체를 말한다. 주로 매개변수 목록을 채우는 데 사용된다.

4. 가짜(Fake)

  • 메모리 데이터베이스처럼 실제로 작동하는 구현 객체가 있지만 실제 배포에는 적합하지 않는 객체를 말한다.

5. 스파이(Spy)

  • 호출되면서 호출된 메서드에 대한 정보를 일정한 방식으로 기록하는 객체를 말한다.

JUnit

  • Junit이란 Java를 위한 대표적인 단위 테스팅 프레임워크이다.

JUnit 생명 주기

  • Junit 테스트의 시작부터 종료까지의 과정을 말한다. 각 테스트마다 필요환 환경을 준비하고 테스트가 끝나면 사용한 리소스를 해제하여 각 테스트간의 독립성을 보장한다.

@Beforeach

  • 각 테스트 실행 전에 수행되는 작업을 정의한다.

@AfterEach

  • 각 테스트 메서드 실행 후에 수행되는 작업을 정의한다.

@BeforeAll, @AfterAll

  • 테스트 클래스의 시작과 종료 시점에 한 번씩만 수행되는 작업을 정의한다.

Assert API

  • 테스트 코드에서 코드의 특정 부분이 예상한 대로 동작하는지 확인하기 위해 Assert를 사용한다. 만약 Assert로 설정한 조건이 충족되지 않으면 테스트는 실패한다.
    - assertEquals(expected, actual);
    - assertNotEquals(unexpected, actual);
    - assertTrue(condition);
    - assertFalse(condition);
    - assertNull(object);
    - asssertNotNull(object);
    - assertSame(expected, actual);
    - assertNotSame(unexpected, actual);
    - assertArrayEquals(expectedArray, actualArray);
    - assertThrows(expectedException, executable);

AssertJ

  • Junit은 Java를 위한 대표적인 단위 테스트 프레임워크인 반면, AssertJ는 Fluent Assertion API를 통해 테스트 검증을 더 읽기 쉽고 자연스럽게 작성할 수 있도록 도와주는 자바 라이브러리이다.
// ret이 10인지 검증
org.junit.jupiter.api.Assertions.assertEquals(10, ret);
Assertions.assertThat(ret).isEqualTo(10);
  • AssertThat 이후 다양한 조건으로 메소드 체이닝을 할 수 있어 유연한 검증이 가능하다.
Assertions.assertThat("The Lord of the Rings").isNotNull()
        .startsWith("The")
        .contains("Lord")
        .endsWith("Rings");
  • 다양한 체이닝 메소드
    • .isEqualTo
    • .isNotNull
    • .isGreaterThan
    • .contains
    • .startsWith
    • .endsWith

Given-When-Then 패턴

  • 테스트의 구조를 명확하게 나타내기 위해 사용된다. 테스트 준비, 실행, 검증 단계로 구분할 수 있다.
@DisplayName("자연수 더하기")
@Test
void addNumbersReturnNumber() {
    //given
    Calculator calc = new Calculator();

    //when
    int ret = calc.add(5, 5);

    //then
    Assertions.assertThat(ret).isEqualTo(10);
}
  • 위의 예시에는 계산기 객체가 주어지고(given), 덧셈으로 두 자연수를 더한 뒤(when) 결과값이 10이 맞는지 검증(then)하는 코드이다.

참고자료

profile
꾸준하게

0개의 댓글