TDD시작하기_최범균

네코·2022년 7월 17일
0
  1. TDD 개발 준비
    TDD를 하려면 지정한 방식으로 코드를 작성하고 실행할 수 있는 도구가 필요

TDD 시작

TDD이전의 개발

  1. 만들 기능의 설계를 고민
    클래스와 인터페이스, 각 각의 메서드 등
  2. 구현에 대해서도 고민
  3. 완료된 것 같을 때 기능을 테스트.

문제

  1. 2번 과정에서 한번에 작성한 코드가 길어지면 디버깅 시간도 비례해 증가
  2. 코드 작성자와 코드 테스터가 다를 경우가 생긴다.
  3. 테스트 과정이 쉽지않다 서버 구동 및 DB 쿼리 등 선행될 작업이 많다.

TDD란

테스트를 먼저하고 구현한다.
테스트를 먼저한다는 것은 기능이 올바르게 동작하는지 검증하는 테스트 코드를 작성한다는 것

첫번째 테스트

가장 쉽거나 예외적인 것을 첫번째 테스트로 선택한다.

흐름

레드-그린-리팩터
테스트 코드 실패 -> 코드 구현해 테스트 통과 -> 리펙토링

테스트 코드 작성 순서

TDD 기능 명세 설계

사용자에게 제공할 기능을 구현하려면 기능을 크게 입력과 결과로 나눠 생각할 수 있다.

ex) 로그인

  • 입력: 아이디와 암호
  • 결과 : 입력값이 올바르게 일치하면 성공, or 실패

입력

보통 메서드의 파라미터로 전달

결과

여러 형식으로 정의된다.
ex) return 값, 익셉션 등

또한 변경도 포함된다.
ex) 회원가입 기능은 실행 결과로 DB에 회원정보를 추가한다.
이 것은 시스템의 상태를 변경하는 것
이런 변경은 리턴값으로 결과를 알 수 없으므로 테스트 대상 실행 후
변경 대상에 접근하여 결과를 확인해야한다.

설계는 기능 명세에서부터 시작한다.
문서화를 통해 기능 명세를 구체화하고 그 과정에서 입력과 결과를 정의하고 이에 따라 코드를 작성한다.
코드에 반영하는 과정에서 기능 이름,파라미터,리턴 타입 등이 결정된다.

설계 과정을 지원하는 TDD

TDD는 테스트 부터 시작
테스트코드를 만들기 위해서는 다음의 두가지를 할 수 있어야한다.

  • 테스트할 기능을 실행
  • 실행 결과 검증

기능을 실행하기 위해선 메서드 혹은 클래스가 우선적으로 정의되어 있어야한다.
책의 암호 강도 측정과 만료일 계산 예제에선 테스트 코드를 작성할 때 다음 4가지를 고려했다

  • 클래스 이름
  • 메서드 이름
  • 메서드 파라미터
  • 실행 결과

이름을 올바르게 결정하는 것에 대한 시간투자를 아끼지말자

필요한 만큼 설계하기

TDD는 테스트를 통과할 만큼만 코드를 작성한다.

복잡한 상황이나 예외적인 상황에 대해 구체적인 경우를 생각해내어 테스트에 반영할 필요가 있다.

JUnit5 기초

모듈 구성

크게 3가지로 구성되어 있다.

  • JUnit 플랫폼: 테스팅 프레임워크를 구동하기 위한 런쳐와 테스트 엔진을 위한 API를 제공
  • JUnit 주피터: JUnit 5를 위한 테스트 API와 실행 엔진을 제공한다.
  • JUnit 빈티지: JUnit 3,4로 작성된 테스트를 JUnit5 플랫폼에서 실행하기 위한 모듈을 제공

@Test a애노테이션, 테스트 메서드

테스트 클래스의 이름은 구분하기 쉽게 Test를 접미사로 붙인다.
테스트를 실행할 메서드에는 @Test 애노테이션을 붙이고 private이면 안된다.
assert 메서드는 실패하면 다음 코드를 실행하지 않고 바로 익셉션을 발생한다.

주요 단언 메서드

assertEquals(expected,actual) : 값이 같은지 검사
assertNotEquals(unexpected,actual)
assertSame(Object expected,Object actual) : 동일 객체인지 검사
assertNotSame(Object unexpected,Object actual)

assertTrue(boolean condition)
assertFalse(boolean condition)
asertNull(Object actual)
assertNotNull(Object actual)
fail() : 테스트를 실패 처리한다.

assertThrows(Class<t'> expectedType,Executable executable)
=>executable을 실행한 결과로 지정한 타입의 익셉션이 발생하는지 검사한다.
발생한 익셉션객체를 리턴한다. 따라서 발생한 익셉션에 대한 추가 검증이 필요한 경우 사용하면된다.

assertAll(): 모든 검증을 실행하고 그 중에 실패한 것이 있는지 확인할 때 사용한다.

테스트 라이프 사이클

실행 순서

  1. 테스트 메서드를 포함한 객체 생성
  2. (존재하면) @BeforeEach 애노테이션이 붙은 메서드 실행
  3. @Test 애노테이션이 붙은 메서드 실행
  4. (존재하면) @AfterEach 애노테이션이 붙은 메서드 실행

@Test 메서드를 실행할 때마다 위의 사이클과 같이 실행된다.

  • @BeforeAll, @AfterAll
    정적 메서드에 붙여 클래스의 모든 테스트 메서드 실행 전후 한번만 실행한다.

테스트 메서드 간 실행 순서 의존과 필드 공유하지 않기

  1. 테스트 메서드가 특정 순서대로 실행된다는 가정하에 테스트 메서드를 작성하면 안된다.
  2. 테스트 메서드가 서로 필드를 공유하는 것도 안된다.

=> 그렇지 않을 경우 테스트 코드 유지보수를 어렵게 만든다.

추가 애노테이션: @DisplayName, Disabled

자바는 메서드 이름에 공백 or 특수 문자를 사용할 수 없기 때문에 메서드 이름만으로
테스트 내용을 설명하기 부족할 수 있다.

  • @DisplayName 애노테이션을 사용해 테스트에 표시 이름을 붙일 수 있다.
  • @Disabled 애노테이션이 붙으면 테스트 실행 대상에서 제외한다.

테스트코드 구성

구성요소

상황, 실행, 결과 확인

상황이 주어지고, 해당 상황에서 기능을 실행하고, 결과를 확인하는 기본 골격
(given when then)

대역

테스트 대상이 아닌 외부 요인은 테스트 코드에서 다루 힘들다.
테스트를 작성하다 보면 외부 요인이 필요한 경우가 있다

  • 테스트 대상에서 파일시스템 사용
  • 테스트 대상에서 DB 조작
  • 테스트 대상에서 외부 HTTP 서버와 통신

=>이렇게 테스트 대상이 외부 요인에 의존하면 테스트 작성, 실행이 어렵다.
8. 테스트 가능한 설계
9.테스트 범위와 종류
10. 테스트 코드와 유지보수
11 마치며

0개의 댓글