본문 바로가기
Group Study (22-23)/TDD

[TDD] 5. 테스트 코드의 구성

by 큐범 2023. 2. 2.

작성자 : 한규범

 

기능에서의 상황

주어진 상황에 따라 기능 실행 결과는 달라진다. 이는 테스트 코드 구조에도 영향을 주는데 이에 관한 내용을 이어서 살표보자.

상황 찾기

노련한 개발자는 어떤 상황이 실행 결과에 영향을 줄 수 있는지 찾기 위해 노력한다. 결과에 영향을 줄 수 있는 상황을 고려하지 않고 작성한 코드는 버그를 포함할 가능성이 크기 때문이다. 다양한 예외 상황을 찾아내고 이를 코드에 반영해야 기능이 비정상적으로 동작하는 것을 막을 수 있다. 결과에 영향을 줄 수 있는 모든 상황을 완벽하게 찾기 힘들 수도 있지만 가능한 많은 예외 상황을 찾기 위해 노력해야 한다.

 

테스트 코드의 구성 요소 : 상황, 실행, 결과 확인

어떤 상황이 주어지고, 그 상황에서 기능을 실행하고, 실행한 결과를 확인하는 세 가지가 테스트 코드의 기본 골격을 이루게 된다.

상황 : given

실행 : when

결과 확인 : then

@Test
void meetsOnlyUpperCreteria_Then_Week(){
    //실행
    PasswordStrengthMeter meter = new PasswordStrengthMeter();
    PasswordStrength result = meter.meter("abcDef");
    //결과 확인
    assertEquals(PasswordStrength.WEAK,result);
}

실행 결과를 확인하는 쉬운 방법은 리턴 값을 사용하는 것이다. 위 코드에서도 암호 강도를 측정한 결과를 리턴 값으로 받아 이 값을 확인했다. → 실행 결과가 항상 리턴값으로 존재하는 것은 아니다.

상황-실행-결과 확인 구조에 너무 집착하지는 말자. 이 구조가 테스트 코드를 작성하는데 도움이 되는 것은 맞지만 모든 테스트 메서드를 이 구조로 만들어야 하는 것은 아니다. 테스트 코드를 보고 테스트 내용을 이해할 수 있으면 된다.

 

외부 상황과 외부 연결

상황 설정이 테스트 대상으로 국한된 것은 아니다. 상황에는 외부 요인도 있다.

@Test
void noDataFile_Then_Exception(){
    File dataFile = new File("badpath.text");
    Assertions.assertThrows(IllegalStateException.class,
            () -> MathUtils.sum());
}

해당 파일이 존재할 수 있다. 테스트는 실행할 때마다 동일한 결과를 보장해야 하는데 우연에 의해 테스트 결과가 달라지면 동일한 결과를 보장할 수 없다. 이는 테스트를 신뢰할 수 없게 만들어 테스트 결과를 무시하게 만드는 요인이 될 수 있다.

테스트 대상이 아닌 외부에서 결과를 확인해야 할 때도 있다. 예를 들어 처리 결과를 지정한 경로의 파일에 저장하는 기능을 생각해보자. 이 기능을 실행한 결과를 검증하려면 해당 경로에 파일이 원하는 내용으로 만들어졌는지 확인해야한다.

 

외부 상태가 테스트 결과에 영향을 주지 않게 하기

TDD를 진행하는 동안에도 계속 실행하고 개발이 끝난 이후에도 반복적으로 테스트를 실행해서 문제가 없는지 검증한다. 그렇기 대문에 테스트는 언제 실행해도 항상 정상적으로 동작하는 것이 중요하다. 간헐적으로 실패하거나 다른 테스트 다음에 실행해야 성공하면 테스트를 믿을 수 없게된다.

@Test
    void dupIdTest() {
        RegistReq req = new RegistReq("kbhandup", "한규범");
        Assertions.assertThrows(DuplicateIdException.class,
                () -> registerService.register(req));
    }

    @Test
    void registerSuccessfully(){
        RegistReq req = new RegistReq("kbhan", "한규범");
        registerService.register(req);
        Member mem = memberRepo.findById("kbHan");
        Assertions.assertEquals("한규범", mem.getName());
    }

dupIdTest() 테스트를 검증하려면 DB의 회원 테이블에 아이디가 “kbjandup”인 데이터를 미리 추가해야 한다. 그래야 아이디 중복 여부를 확인하는 dupIdTest()가 올바르게동작한다.

실패 상황

가정 : 아이디가 “kbhan”인 데이터가 없는 상태에서 registerSuccessfully() 가 통과한다.

상황1 : 가정에서 DB회원 테이블에 아이디가 “kbhan”인 데이터가 생성된다.

상황2 : 상황1에서 한번 더 registerSuccessfully() 를 실행하면 이미 “kbhan”은 있는 아이디로 테스트가 실패한다.

결과 : DB 데이터의 상태에 따라 테스트가 성공/실패가 갈리는 경우도 있다.

 

외부 상태와 테스트 어려움

상황과 결과에 영향을 주는 외부 요인은 파일, DBMS, 외부 서버 등 다양하다. 이들 외부 환경을 테스트에 맞게 구성하는 것이 항상 가능한 것은 아니다.

실행결과가 외부 시스템에 기록되는 경우가 있다.

테스트 대상이 아닌 외부 요인은 테스트 코드에서 다루기 힘든 존재이다. 외부 상황은 테스트 코드에서 마음대로 제어할 수 없는 경우가 있다. 또한, 테스트 코드에서 생성한 외부 결과를 마음대로 초기화하기 힘들 때도 있다. 이렇게 테스트 대상의 상황과 결과에 외부 요인의 관여할 경우 대역을 사용하면 테스트 작성이 쉬워진다. 대역은 테스트 대상이 의존하는 대상으로 실제 구현을 대신하는 구현인데 이 대역을 통해서 외부 상황이나 결과를 대체할 수 있다.

 

git issue.

 

6주차 - 테스트 코드의 구성 · Issue #56 · GDSC-MYONGJI/22-23-TDD-Study

⭐ Chapter 6. 테스트 코드의 구성 테스트 코드의 구성에 대해 알아본다 테스트 코드의 구성을 알아보고 여러 상황에서의 테스트 코드를 작성해보기 Chap 6의 내용을 개인 기술 블로그에 정리한 후

github.com

 

Reference.

 

테스트 주도 개발 시작하기 - YES24

TDD(Test-Driven Development)는 테스트부터 시작한다. 구현을 먼저 하고 나중에 테스트하는 것이 아니라 먼저 테스트를 하고 그다음에 구현한다. 구현 코드가 없는데 어떻게 테스트할 수 있을까? 여기

www.yes24.com

 

'Group Study (22-23) > TDD' 카테고리의 다른 글

[TDD] 7. 테스트가 가능한 설계  (0) 2023.03.03
[TDD] 6. 대역  (1) 2023.02.24
[TDD] 4. JUnit 5 기초  (3) 2023.01.27
[TDD] 3. TDD ∙ 기능 명세 ∙ 설계  (3) 2023.01.21
[TDD] 2. 테스트 코드 작성 순서  (1) 2023.01.17