[우아한테크세미나] 2021년 3월 우아한테크세미나 - 우아한 ATDD by 류성현님

8 분 소요

세미나 : 2021년 3월에 진행된 우아한테크세미나 발표 중 “우아한 ATDD”에 대해 내용을 정리해 보도록 하겠다.

ATDD 사용 계기

평소 팀원들과 페어 프로그래밍으로 진행할 때는 피드백을 통해 서로의 학습에 도움이 되고 집중력을 향상 시켜 코드 품질을 늘릴수 있다.

그러나 혼자서 개발을 진행해야 하는 경우 이러한 피드백을 즉각적으로 받을 수 없다는 문제점이 존재한다.

인수 테스트의 도움

  • 배포 없이 받는 빠른 피드백
  • 새로운 팀의 도메인과 서비스 흐름을 파악하는데 큰 도움이 됨
  • 도메인 이해에 예상보다는 짧은 시간이 소요

without 인수 테스트

  • 배포해서 기능 동작 확인
  • 페이지에서 테스트
  • 수동으로 변경 사항을 확인

with 인수 테스트

  • 배포없이 테스트로 대부분 검증 가능
  • 인수 테스트로 스펙 표현 가능

스펙을 인수 테스트로 표현 가능하다는 점에서 큰 장점을 느꼈다. 평소 개발을 하다보면 기획의 내용을 일부 빠트리는 개발이 이루어질 때가 많은데 보통 개발이 완료된 후에 피드백을 받게 되는데 이는 개발 전부터 설계가 기획을 반영했는지에 대해 팀원들이 명확히 피드백 할 수 있어 좋은것 같다.

빠른 피드백

  • 새로운 문화들의 공통점은 빠른 피드백을 받는 방법
  • 든든한 지원군과 함께 코딩을 하는 느낌을 받음
  • 자신감을 주는 자동화된 테스트

ATDD가 TDD를 포함하고 있기에 TDD의 장점을 그대로 발휘할 수 있는것 같다.

피드백을 받는 방법

  • 페어 프로그래밍
  • 테스트 / 인수 테스트
  • 코드 리뷰
  • 배포
  • 출시

보통은 프로젝트를 진행하며 코드리뷰, 배포를 통한 피드백을 가장 많이 접하는 것 같다.

테스트/인수 테스트 단계에서 피드백을 받게 되면 피드백 받는 시점을 좀 더 앞으로 당길 수 있고 자가진단이 가능하기 때문에 부수적인 시간낭비가 많이 제거될 것 같다.

즉, 다른 사람이 아닌 본인이 본인을 테스트…! 만약 코드 리뷰, 배포 단계에서 문제점을 발견하지 못하면 출시 이후 문제가 발생하기 때문에 이는 운영에 크리티컬한 문제를 야기할 것 같다. 사전에 테스트/인수 테스트 단계에서 예방하자!!

테스트 주도 개발

image

실패하는 단위 테스트 작성 -> Pass 하도록 테스트 변경 -> 리펙토링 -> ...

  • 테스트를 설계 활동으로 바꾸는 효과
  • 이로 인해 설계 품질에 관한 피드백도 빠르게 받게 도와줌

아쉬운 부분

  • 어떻게 시작? 언제 끝?
  • 각 단위들이 잘 통합하는지?

TDD를 하다보면 어느정도까지 테스트되어야 하는지 애매할때가 많다. 이러한 “어느정도까지 테스트가 되어야 한다는 것”에 대한 기준을 명확히 정의한 것이 ATDD 라고 생각이 든다.

TDD의 표면적 의미는 “테스트가 개발을 주도한다.”인 반면, ATDD의 표면적 의미는 “인수조건을 검증하는 테스트가 개발을 주도한다.”라는 점에서 테스트 대상을 특정지었다고 생각한다.

인수 테스트 주도 개발

image

장점

  • 빠른 피드백을 받을 수 있음
  • 회귀 오류를 잡아줄 꾸준한 테스트를 만들 수 있음
  • 기존 기능을 망가뜨리지 않고 새 기능을 추가할 수 있음
  • 인수 테스트를 작성하면서 구현할 대상에 대한 이해도 증진
  • 작업의 시작과 끝이 명확해져서 심리적인 안정감에 도움


ATDD 란?

용어의 지옥에 빠지지 말고 용어의 개념에 집중하여 학습하는 것이 중요하다.

테스트 vs TDD

image

  • 테스트: 구현 -> 테스트(검증)
    • 일과가 끝나고 마치 일기를 쓰는 느낌
  • TDD: 테스트(요구사항) -> 구현 + @
    • 일과 시작전 TODO 리스트를 작성하는 느낌

TDD vs BDD

image

TDD를 조금 더 잘 설명하기 위해 나온 것이 BDD다.

테스트를 검증의 대상이 아닌 행위로 관점을 변경한 것이다. (given-when-then으로 선언)

BDD와 TDD의 차이점은 사실 크게 없다고 생각한다. 단지 TDD의 목적을 제대로 이해하지 못한체 막무가내로 테스트를 작성해나가는 이들를 위해 TDD의 본질적인 목적을 표면적으로 드러내 단어로 부터 목적을 느낄 수 있도록 BDD 라고 지칭한 것 같다.

TDD vs BDD vs ATDD

image

기획, 개발, QA 등 여러 직군이 함께 공통의 이해를 하기 위해 만들어진 개발 방법론이다.

인수 조건을 다함께 정의한다.

다 같이 인수 조건을 정의하는 이유

  • 기획 -> 개발 -> QA 넘어가는 흐름에서 뒤늦게 피드백을 받고 반영 됨
  • 처음부터 서로의 의견을 합쳐 나중에 들게될 리소스를 Save 하자

기획, 개발, QA의 생각이 일치해야 한다는 점을 굉장히 중요하게 생각하고 있었다. 모든 개발이 완료되어 QA를 진행하다 보면 그제서야 서로가 생각하고 있던것이 다르다는 것을 깨닫고 QA 항목이 마구마구 쏟아져 나온다… 뿌리에서부터 제대로 한 줄기로 뻗어나간다면 평화로운 QA 시간이 될 것 같다.

ATDD 프로세스

image


ATDD 개발 프로세스

  1. 인수 조건 정의
  2. 인수 테스트 작성
  3. 기능 구현

예시 - 강의 수강 대기 신청

인수 조건

  • 인수 테스트가 충족해야하는 조건
  • 표현 포맷
    • 시나리오 기반
    • ex. Given / When / Then
given
    강사는 강의를 생성했다.
    강사는 강의를 신청 가능 상태로 변경하였다.
    강의 모집인원 만큼 신청을 받았다. 
when
    회원이 수강 대기 신청을 요청한다. 
then
    회원은 강의의 수강 대기자로 등록 되었다.

인수 테스트

  • 인수 조건을 검증하는 테스트
  • 실제 요청/응답하는 환경과 유사하게 테스트 환경을 구성

image

기능 구현

  • 인수테스트를 충족하기 위한 코드 구현
  • 기능 구현은 TDD로 진행할 수 있음


ATDD 관련 경험한 고민들

인수 조건 만들기

요구사항(사용자 스토리)

  • 누가 -> 왜 -> 무엇을
  • ex. 강사는 -> 강의료를 환불해주기 위해 -> 수강생의 수강을 취소 할 수 있다.

인수 조건 표현

  • given: 사전 조건
  • when: 검증 대상
  • then: 기대 결과

인수 조건 작성

  • 검증 하고자 하는 when 구문 먼저 작성
  • 기대 결과를 의미하는 then 구문 작성
  • when과 then에서 필요한 정보를 given을 통해 마련

인수 조건 예시

  • ex. 강사는 -> 강의료를 환불해주기 위해 -> 수강생의 수강을 취소 할 수 있다.
given
    수강생이 수강 신청을 하였다.
    과정의 남은 기간이 절반 이상이다. 
when
    강사는 특정 수강생의 수강 상태를 취소 요청을 한다.
then
    특정 수강생의 수강 상태가 취소 된다. 특정 수강생의 결제 내역이 환불 된다.

이슈 관리

image

인수 테스트 특징

  • Black Box 테스트
    • 내부 구조나 작동과 연관이 없는 테스트
  • UI 레벨 대신 API 레벨 인수 테스트
    • 백엔드 개발자 입장에서 공수가 너무 많이 든다고 판단됨(UI는 자주 변경 되기 때문)
    • UI 레벨이 아닌 API 레벨에서 인수 테스트를 작성

테스트 도구

  • 테스트 서버(환경)
    • @SpringBootTest
  • 테스트 클라이언트
    • 서버에 요청을 보내는 클라이언트
    • MockMVC, WebTestClient, RestAssured

SpringBootTest

  • 테스트 환경에서 요청에 대한 응답을 하기 위한 설정
  • SpringExtension을 통해 Spring Test Context 를 사용할 수 있음.
  • SpringBootTestContextBootstrapper
    • SpringBootConfiguration 자동 맵핑
    • webEnvironment 지원: 테스트 환경에서 웹서버 환경 설정 가능하도록 함.

webEnvironment

  • 테스트의 웹 환경을 설정하는 속성(기본값: MOCK)
  • 4가지 속성 존재: MOCK, RANDOM_PORT, DEFINED_PORT, NONE
  • 실제 웹 환경과 유사한 RANDOM_PORT 설정 선택
    • 웹 환경: 톰켓, 네티와 같은 요청과 응답을 주고받는 서버 환경(RANDOM_PORT, DEFINED_PORT에서 사용가능)

테스트 객체

  • 테스트를 위한 서버에 요청을 보내기 위한 클라이언트 객체 설정
  • ex. MockMvc, RestAssured, WebTestClient

MockMvc, RestAssured, WebTestClient

  • MockMvc
    • @SpringBootTest의 webEnvironment.MOCK과 함께 사용 가능하며 mocking 된 web environment 환경에서 테스트
  • WebTestClient
    • @SpringBootTest의 webEnvironment.RANDOM_PORTDEFINED_PORT와 함께 사용, Netty를 기본으로 사용
    • webflux 안에 존재하는 객체로 Tomcat이 아닌 Netty가 뜸
  • RestAssured
    • 실제 web environment(Apache Tomcat)을 사용하여 테스트

테스트 환경 + 테스트 클라이언트 조합

  • @SpringBootTest / Mock + MockMVC
  • @SpringBootTest / RANDOM_PORT + RestAssured

<예시>

image

테스트 데이터 초기화

repository 활용하여 데이터 초기화?

  • 손쉽게 데이터 초기화가 가능
  • 구현이 달라지면 테스트 영향을 받음(내부 구현 의존성 증가)
  • 유효성 검사 로직 없음(초기화 데이터 보장 불가)
  • 깨지기 쉬운 테스트가 될 가능성이 높음

요청을 통한 데이터 초기화

  • 테스트 객체를 이용하여 직접 호출 후 초기화

image

테스트가 다른 테스트에 영향을 주는 상황

image

  • 첫 테스트에서만 Context를 load하고 이 후 테스트는 캐싱된 Context를 사용하기 때문에 빠름. 그치만 캐싱으로 인해 다른 테스트에 영향을 준다.

@DirtiesContext

  • 스프링 테스트 환경에서 캐싱된 Context를 사용하지 않게 설정
  • 매번 Context를 새로 구성하다보니 시간이 많이 걸림
  • 사용하지 않는 것이 좋음.

일괄적인 데이터 초기화

  • EntityManager를 활용하여 테이블 이름 조회
  • 각 테이블 Truncate 수행
  • ID auto increment 값 초기화

<예시>

image

중복 처리 & 가독성 개선 필요

테스트 코드 가독성의 중요성

image

  • 하나의 테스트가 152 line ~ 404 line
  • 가독성이 좋지 않으면 방치될 가능성이 높음 (결국 @Disabled 처리됨)

메서드 분리

  • 반복되는 코드는 메서드로 분리

image

다른 인수 테스트에서 재사용

step 메서드(given, when, then)를 별도의 step 클래스로 분리하여 다른 인수테스트 클래스에서 재사용한다.

image

가독성 증진 - 한글 메서드 네이밍

  • 의도 드러내기

image

인수 테스트 리팩터링 후

image

  • @DisplayName: 메서드 명으로 충분히 설명되지 않을 때 추가적인 설명을 위해 주석의 역할로 사용

중복 검증?

image

  • 하단의 인수테스트가 제대로 검증되지 않을 수 있음.
    • given의 유료_강의_수강_신청의 응답이 404가 떳지만, when의 유료_강의_수강_신청이 통과하면 정상적으로 동작하지는 않지만 테스트는 Pass 된 것으로 인지

해당 부분을 검증 메서드로 따로 분리하여 제거하여 해결한다.

image

image

  • 유료_강의_수강_신청되었음이라는 then이 포함된 검증 메서드를 통해 given에 대해서도 검증이 가능하다.

외부 API 호출

외부 API를 실제로 호출 할 것인가, 가짜로 할 것 인가에 대한 고민…

두 가지 모두 상황에 따라 다르게 구축하기로 결정하였다.

Github API 연동

  • 테스트 계정으로 실제 요청
  • 대기 시간이 필요한 경우
  • 외부 서비스 장애시 테스트 불가능

결제 API 연동

  • 실제가 아닌 Fake 서비스에 요청하도록 구성
  • 결제 API 요청을 처리하는 컨트롤러를 별도로 생성

image


인수 테스트 작성 팁

간단한 성공 케이스 우선 작성

  • 동작 가능한 가장 간단한 성공 케이스로 시작
  • 테스트가 동작하면 더 좋은 생각이 떠오를 수 있음

인수 테스트 클래스

  • 같은 테스트 픽스처를 공유하는 인수 테스트를 클래스 단위로 묶음
    • 도메인 별로 실제로 given이 필요한지 여부를 파악하기 쉬움

인수 테스트 다음 TDD

인수 테스트 주도 개발

image

Outside In TDD

  • BDD 에서는 Outside In 방식의 TDD를 말한다.
  • 인수 테스트 작성 후 세부적인 도메인 설계를 이어나간다.

도메인 부터 TDD

  • 인수 테스트를 통해 시나리오 및 전반적인 기능에 대한 이해를 했다면
  • 핵심 기능에 대한 도메인 설계를 한 후 도메인 객체에 대한 TDD를 수행

추천하는 흐름

  • Top-Down으로 방향을 잡고, Bottom-Up으로 구현하기
  • 인수 테스트 작성을 통해 요구사항과 기능 전반에 대한 이해를 선행
  • 내부 구현에 대한 설계 흐름을 구상
  • 설계가 끝나면 도메인부터 차근차근 TDD로 기능 구현
  • 만약 도메인이 복잡하거나 설계가 어려울 경우 이해하고 있는 부분 먼저 기능 구현
  • 인수 테스트의 요청을 처리하는 부분부터 진행할 수 있음


ATDD 도입하기

나혼자 ATDD

  • 토이 프로젝트로 경험 쌓기
  • 간단한 기능부터 적용해보기
  • 경험해보면서 상황에 맞는 방법 찾기

다함께 ATDD (in 개발팀)

  • ATDD 개발 프로세스 룰 정하기(인수 조건, 포맷 등)
  • 팀 회의와 회고를 통한 피드백
  • 살아있는 규칙 정하기

성공적인 ATDD 적용을 위해

  • 아주 쉽게 시작할 수 있는 부분부터 도입
  • 조금씩 상황에 맞게 조정
  • 가벼운 프로세스부터 시작, 문제점 발견 시 민첩하게 대응

레거시 기반 인수 테스트 작성하기

  • 먼저 인수 테스트를 작성하여 기존에 구현된 기능을 보호하기

인수 테스트 작성 가이드

image

image

지속적인 피드백으로 유연하게 환경에 맞는 가이드를 작성해 나간다.

기획 & QA와 함께하는 ATDD

  • 기획, QA 설득하기(장점 소개)
  • 다같이 만드는 요구 사항
  • ATDD 적용 전과 후, 장단점

왜 좋은지 설득하기

  • 개발 친화적인 용어는 제외하고 설명하기
  • 기존 방식과 비교하여 장점 이야기 하기

함께 만드는 인수 조건 - Discuss 회의

  • 기획/개발/QA 함께 인수 조건 회의 참여
  • 화면 기반으로 작성할 경우 이해도가 높음
  • 모든 인수 조건을 다같이 만드는건 비효율적

ATDD 적용 전과 후, 장단점

  • 장점
    • Common Understanding
      • 다른 포지션의 관점은 물론 업무 프로세스도 간접적으로 익힐 수 있음
      • 다른 포지션의 진행 상황에 대한 인지와 이해도가 높아짐
  • 단점
    • 인수 조건 정의 어려움
      • 문서를 어떻게 관리해야 할 지에 대한 고민이 필요
    • 리소스
      • (기획/개발) 두번 작업하는 느낌을 받음

마무리

  • 좋은 내용이지만 막상 도입하기 어려움
  • ATDD 자료가 부족(21. 04. 기준) - Best Practice 참고의 어려움


고찰

평소 TDD의 목적과 사상에 대해 매우 긍정적인 생각을 가지고 있었다. 그리고 어떻게 하면 기획을 설계에 잘 적용할 수 있을지에 대한 고민도 많이 하고 있었는데, ATDD를 접하게 되면서 개발자 친화적인 목적을 가진 TDD의 한계를 벗어나 기획 친화적인 실용적인 개발 방법론을 수행할 수 있게 되는 것같다.

물론 아직 TDD도 제대로 수행하고 있지 못하지만, ATDD는 TDD를 도입하는 시작부분에 ‘인수’라는 개념이 추가된 정도로 생각이 들어 ATDD를 연습하는 것이 곧 TDD를 연습하는 것과 같다고 생각이 든다.

현재 업무를 수행하며 프로젝트에 접목시키기에는 지식과 경험이 부족하기에 무턱대고 도입할 수 없을 것 같아 간단한 요구사항을 구현하는 토이프로젝트에 개인적인 연습을 통해 점진적으로 팀내에 전파하는 방식으로 발전시켜 나가볼 예정이다.

매번 느끼지만 ‘우아한테크세미나’는 최근이 아닌 몇년이 지난 세미나에서도 실무에 도움이 되는 굉장히 유익한 주제를 다룬다고 생각한다. 차근 차근 다른 세미나에 대해서도 정리해보도록 하겠다.


참고

댓글남기기