티스토리 뷰

나의 공부방

[개발서적] Test-Driven Development: By Example(테스트 주도 개발) 내용 정리 - 방법 (2)

망나니개발자 2021. 4. 19. 15:07
반응형

2. xUnit 예시


이번에는 TDD로 테스트를 위한 프레임워크를 작성해볼 계획이다. 테스트 프레임워크의 할 일 목록에는 setUp 메소드 호출하기, 나중에 tearDown 메소드 호출하기, 테스트가 실패해도 tearDown 호출하기, 여러 개의 테스트 실행하기, 수집된 결과를 출력하기 등이 있을 것이다.

(자세한 예제는 책을 참고하기를 바라고, 기억해둘만한 내용만 정리하도록 하자.)

 

[ 19. 테이블 차리기 ]

테스트 사이의 커플링은 확실히 지저분한 결과를 야기한다. 한 테스트가 깨지면, 다음 열 개의 테스트가 올바르더라도 같이 깨지기 때문이다. 또한 테스트의 순서에 의존적이라면 더욱 어려운 문제를 야기할 수 있다. 그렇기에 테스트 커플링을 만들지 말아야 한다.

 

[ 22. 실패 처리하기 ]

실제 코드가 수정되는 경우는 실패한 테스트 코드가 존재하는 경우이다. 우리는 항상 테스트를 먼저 작성해야 한다는 사실을 의식적으로 상기해야 한다.

 

 

3. 테스트 주도 개발의 패턴


[ 25. 테스트 주도 개발 패턴 ]

어떻게 테스트할 것인가에 대하여 자세히 이야기하기 전에 기본적인 전략에 관한 질문에 답을 해야 한다.

  • 테스트한다는 것은 무엇을 뜻하는가?
  • 테스트를 언제 해야 하는가?
  • 테스트할 로직을 어떻게 고를 것인가?
  • 테스트할 데이터를 어떻게 고를 것인가?

 

테스트(명사)

작성한 소프트웨어를 테스트하기 위해서는 자동화된 테스트가 필요하다.

테스트하다는 것은 평가한다는 뜻이다. 대부분의 소프트웨어 엔지니어들은 아무리 작은 변화라도 테스트하지 않고 릴리즈 하지 않는다. 하지만 여기서 중요한 것은 테스트를 하는 것과 테스트를 갖는 것은 다르다는 것이다. 갖고 있는 테스트를 수시로 실행하면 작업 중에 에러를 낼 확률도 줄어들고, 스트레스를 줄일 수 있다.

 

 

격리된 테스트

테스트를 실행하는 것은 서로 영향을 주지 않아야 한다.

격리된 테스트가 암묵적으로 내포하는 특징 중 하나는 테스트가 실행 순서에 독립적이게 된다는 점이다. 테스트의 일부만 실행하고 싶은 경우에도 선행 테스트에 의해 영향을 받지 않아야 한다.

그 외에 테스트의 격리는 주어진 문제를 작은 단위로 분리하도록 노력하여 각 테스트를 실행하기 위한 환경을 쉽고 빠르게 세팅할 수 있게 한다는 특징을 지닌다.

테스트를 격리함으로써 응집도는 높고 결합도는 낮은 객체의 모임으로 시스템이 구성된다.

 

 

테스트 목록

TDD를 하면 구현해야 할 것들에 대한 테스트 목록과 리팩토링 목록을 적게 된다. 그리고 이후에는 한 번에 한 개의 작업만을 진행함으로써 TDD를 진행하면 된다. 진행하면서 테스트를 통과하게 만드는 과정에서 새롭게 작성된 코드들은 새로운 테스트가 필요함을 알려줄 것이다. 이 새 테스트 역시 할일 목록에 적어 놓아라.

 

 

테스트 우선

테스트는 테스트 대상이 되는 코드를 작성하기 직전에 작성하는 것이 좋다. 그리고 코드를 작성한 후에는 테스트를 만들지 않을 것이다.

 

 

단언(Assert) 우선

테스트를 작성할 때 Assert는 가장 먼저 작성하는 것이 좋다.

Assert를 먼저 작성하면 작업을 단순하게 만드는 강력한 효과를 볼 수 있다.

 

 

테스트 데이터

테스트를 할 때에는 쉽고 따라가기 좋을 만한 데이터를 사용해야 한다.

테스트 작성에도 청중이 존재한다. 단순히 데이터 값을 산발하지 말고, 데이트 간에 차이가 있다면 의미가 있어야 한다. 또한 실제 데이터를 사용하는 것다 상당히 유용하다.

 

 

명백한 데이터

데이터의 의도를 표현하기 위해서는 테스트 자체에 예상되는 값과 실제 값을 포함시키고, 이 둘의 관계를 드러내도록 노력해야 한다.

테스트를 작성할 때는 컴퓨터 뿐만 아니라 후에 코드를 읽을 다른 사람도 생각해야 한다. 코드에 되도록 많은 실마리를 남기면 이해가 쉬워진다.

 

 

[ 26. 빨간 막대 패턴 ]

한 단계 테스트

다음 테스트를 고르는 기준은 다음 단계로 나아갈 수 있으면서, 구현할 수 있다는 확신이 들어야 한다.

 

 

설명 테스트

자동화된 테스트가 더 널리 쓰이게 하려면 테스트를 통해 설명을 요청하고 테스트를 통해 설명해야 한다.

무언가 설명이 필요하다면 테스트를 이용하여 묻고, 테스트를 이용하여 설명하면 테스트가 더욱 널리 사용될 것이다.

 

 

학습 테스트

주제에서 무관한 아이디어가 떠오르면 이에 대한 테스트를 할 일 목록에 적어두고 다시 주제로 돌아와야 한다.

생산적인 시간을 위해서는 내가 진행중인 작업을 놓치지 않는 것이 중요하다. 새로운 아이디어가 떠오르면 존중하고 맞이하되, 그것이 내 주의를 흩뜨리지 않게 해야 한다. 그렇기에 우리는 그 아이디어를 리스트에 적어놓고 하던 일로 다시 돌아가야 한다.

 

 

회귀 테스트

시스템 장애가 보고될 때, 그 장애로 인하여 실패하는 테스트와 장애가 수정되었음을 확인할 수 있는 테스트를 가장 간단하게 작성해야 한다.

회귀 테스트란 사실 완벽한 선견지명이 있다면 코딩할 때 작성되었을 테스트이다. 회귀 테스트를 작성할 때는 이 테스트를 작성해야 한다는 사실을 어떻게 하면 애초에 알았을 지 고민해야 한다.

 

 

[ 27. 테스팅 패턴 ]

자식 테스트

지나치게 큰 테스트 케이스를 성공하기 위해서는 원래 테스트 케이스에서 실패하는 작은 테스트 케이스를 작성하고 그 작은 테스트 케이스가 실행되도록 하는 것이다. 그 후에 다시 원래의 큰 테스트 케이스를 추가하자.

작성한 테스트가 너무 크다면 더 좋은 방향을 찾기 위해 노력해야 한다.

 

 

모의 객체

비용이 많이 들거나 복잡한 리소스에 의존하는 객체를 테스트하려면, 모의 객체를 사용하면 된다.

예를 들어 데이터베이스는 시작 시간이 오래 걸리고, 깨끗한 상태로 유지하기 어렵다. 그리고 만약 데이터베이스가 원격 서버에 있다면 테스트 성공 여부는 네트워크에 영향을 받게 된다. 그러므로 모의 데이터베이스를 사용하면 다양한 문제를 해결할 수 있다.

모의 객체를 사용하면 성능과 견고함 등 다양한 이점을 얻을 수 있다.

 

 

셀프 션트

셀프 션트 기법으로 작성한 테스트는 그렇지 않은 테스트보다 데이터 읽기에 수월해진다.

예를 들어 어떤 리스너를 포함하는 테스트 해야 한다면, 그 리스너를 테스트 클래스에 구현하는 것이 셀프 션트이다. 파이썬 같은 낙관적 타입 시스템을 가진 언어라면 이러한 효과를 톡톡히 얻을 수 있다. 하지만 자바와 같은 비관적 타입 시스템을 가진 언어라면 오히려 셀프 션트를 사용한 결과로 인터페이스 안의 온갖 기괴한 메소드들을 다 구현한 테스트들을 보게 될 수 있다.

 

 

로그 문자열

메세지의 호출 순서가 올바른지 검사하려면 로그 문자열을 사용하면 된다.

로그 문자열을 가지고 있다가 메소드가 호출될 때마다 그 문자열에 내용을 추가하면 된다. 로그 문자열은 특히 옵저버를 구현하고, 이벤트 통보가 원하는 순서대로 발생하는지 확인하고자 할 때 유용하다.

 

 

깨진 테스트

혼자서 프로그래밍을 할 때는 마지막 테스트가 실패한 상태로 프로그래밍 세션을 마무리하는 것이 좋다. 그러면 우리는 생각의 실마리를 다시 떠올리고, 어느 작업부터 시작할 것인지 명백히 파악할 수 있다. 즉, 책갈피를 가지게 되는 것이다.

 

 

깨끗한 체크인

반대로 팀 프로그래밍을 할 때에는 모든 테스트가 성공한 상태로 프로그래밍 세션을 마무리하는 것이 좋다.

다른 팀원들과 함께 작업하는 경우라면 상황은 완전히 달라진다. 팀 프로그래밍에서는 안심되고 확신있는 상태에서 시작할 필요가 있다. 따라서 코드를 체키은 하기 전에 항상 모든 테스트가 돌아가는 상태로 만들어 두어야 한다.

 

 

[ 28. 초록 막대 패턴 ]

실패하는 테스트가 있다면 고쳐야 한다. 그리고 빨간 막대를 가능한 빨리 통과시키기 위해 다음의 패턴들을 사용하면 된다.

 

가짜로 구현하기(진짜로 만들기 전까지만)

실패하는 테스트를 만든 후 첫 구현은 상수를 반환하도록 하면 된다. 그리고 테스트가 통과하면 단계적으로 상수를 변수를 사용하도록 변형한다.

가짜로 구현하기를 강력하게 만드는 두 가지 효과가 있다.

  • 심리학적: 빨간 막대와 초록 막대 상태는 완전히 다르다. 막대가 초록색이라면 어느 위치인지 알고 거기부터 리팩토링해 갈 수 있다.
  • 범위 조절: 하나의 구체적인 예에서 일반화를 함으로써, 불필요한 고민으로 혼동되는 일을 예방할 수 있다.

 

삼각 측량

추상화 과정을 테스트로 주도할 때 최대한 보수적으로 하기 위해서는 오로지 예가 2개 이상일 때에만 추상화를 해야 한다. 예를 들어 다음과 같은 덧셈에 대한 테스트가 2개 이상일 때에만 구현을 추상화해야 한다.

public void testSum() {
    assertEquals(4, plus(1, 3));
    assertEquals(7, plus(1, 6));
}

private int plus(int augend, int addend) {
    return augend + addend;
}

삼각 측량이 매력적인 이유는 그 규칙이 매우 명확하기 때문이다. 만약 어떤 계산을 해야 올바르게 추상화할 것인지 감을 잡기 어려울 때 삼각측량을 사용하는 것이 좋다.

 

 

명백한 구현

단순한 연산들은 그냥 구현해버려라.

가짜로 구현하기와 삼각측량은 매우 작은 발걸음이다. 그렇기에 뭘 타이핑해야 할지 알고, 그걸 재빨리 할 수 있다면 그냥 해버려라. 그러다가 만약 손가락이 머리를 따라오지 못하기 시작하면 다른 구현 기법을 사용하라.

 

 

하나에서 여럿으로

객체 컬렉션을 다루는 연산은 일단 컬렉션 없이 구현하고, 그 다음에 컬렉션을 사용하면 된다.

 

 

[ 29. xUnit 패턴 ]

단언(Assertion)

단언(Assertion)은 구체적이여야 한다. 예를 들어 다음과 같은 단언은 0이 아닌 경우라면 항상 성공하므로, 특정 값을 명시해주는 것이 좋다.

public void testArea() {
    assertTrue(rectangle.area() != 0);
    assertEquals(rectangle.area(), 50);
}

 

 

픽스처

테스트를 작성하다 보면 객체를 원하는 상태로 세팅하는 코드들을 작성하게 된다. 하지만 이러한 코드는 다음과 같은 이유로 좋지 않다.

  • 복사/붙여넣기를 하여도 이런 코드를 작성하는 것에 시간이 소요된다. 우리는 테스트를 빨리 작성하길 원한다.
  • 인터페이스를 수동으로 변경할 필요가 있을 경우, 여러 테스트를 고쳐야 한다.

그렇기에 우리는 객체를 설정하는 것을 별도의 메소드로 분리해야 한다.

 

 

외부 픽스처

픽스처 중 외부 자원이 있을 경우에는 테스팅 프레임워크의 tearDown 메소드에 작성해주면 된다.

예를 들어 파일 쓰기와 같은 경우 테스트 이후에 반드시 파일을 닫아야 한다.

 

 

테스트 메소드

예외가 발생하는 것이 정상인 경우에는 예외를 잡아서 무시하고, 예외가 발생하지 않은 경우에 한해 fail() 등을 통해 테스트가 실패하도록 하면 된다.

 

 

예외 메소드

예외가 발생하는 것이 정상인 경우에는 예외를 잡아서 무시하고, 예외가 발생하지 않은 경우에 한해 fail() 등을 통해 테스트가 실패하도록 하면 된다.

 

 

[ 30. 디자인 패턴 ]

커맨드

간단한 메소드 호출이 아닌 복잡한 형태의 계산 작업에 대한 호출이 필요하다면, 계산 작업에 대한 객체를 생성하여 이를 호출하면 된다.

예를 들어 Java의 Runnable 인터페이스는 추상 메소드 run을 갖는데, 이를 이용하면 우리는 모든 변수들을 작업하고 run()의 구현으로 어떤 것을 넣어도 된다.

 

 

값 객체

널리 공유해야 하지만 동일성(Identity)은 중요하지 않은 경우라면, 객체 생성 시에 상태를 설정한 후 절대 변할 수 없도록 하면 된다. 그리고 이 객체에 대해 수행되는 연산은 언제나 새로운 객체(복사본)를 반환하도록 구현하면 된다. 그러면 우리는 객체가 공유되더라도 변하지 않음을 확신할 수 있다.

 

 

Null 객체

객체의 특별한 상황을 표현하고자 한다면, 그 특별한 상황을 표현하는 새로운 객체를 만들면 된다.

만약 객체가 존재하지 않는 상황이라면, null을 반환하는 것이 아닌 EmptyObject를 반환하도록 하면 된다.

 

 

템플릿 메소드

작업 순서는 변하지 않지만 각 작업 단위에 대한 미래의 개선 가능성을 열어두고 싶은 경우에는 다른 메소드들을 호출하는 내용으로만 이루어진 메소드를 만들면 된다.

public void run () throws Throwable {
    setUp();
    try {
        runTest();
    }
    finally {
        tearDown();
    }
}

 

 

플러거블 객체

다른 상황을 표현하는 가장 간단한 방법은 명시적인 조건문을 사용하는 것이다. 하지만 이런 명시적인 의사 결정 코드는 결국 소스의 여러 곳으로 퍼져나가게 될 것이다.

TDD의 두 번째 수칙이 중복을 제거하는 것이기 때문에, 이런 싹을 애초에 잘라버려야 된다. 조건문을 두 번째로 본다면, 플러거블 객체를 끄집어낼 시점이다.

예를 들어 마우스가 하나의 선택을 갖는지, 다중 선택을 갖는지에 따라 다르게 처리를 해주어야 한다면, 해당 코드들을 if-else로 중복시키지 말고, SingleSelection과 MultiSelection 클래스를 통해 다형성으로 처리하면 분기 작업이 줄어들 것이다.

 

 

플러거블 셀렉터

하지만 만약 단지 메소드 하나만 구현해야 하는 경우라면 플러거블 객체로 해결하기에는 무거울 수 있다. 이럴 때는 메소드의 한가지 대안은 switch 문을 갖는 하나의 클래스를 만드는 것이다.

 

 

팩토리 메소드

새로운 객체를 만들 때 유연성을 원하는 경우 팩토리 메소드를 사용하면 된다. 생성자는 자신을 잘 표현하지만, 특히 자바에서 표현력과 유연함이 떨어진다. 

 

 

사칭 사기꾼

기존 클래스에 대한 새로운 구현체를 넣어야 한다면 여러 메소드를 수정해야 될 수 있다.

TDD에서는 크게 두 군데 수정을 필요로 하는데, 하나는 새로운 구현체에 대한 테스트 케이스를 작성하는 것이고 또 다른 하나는 새로운 구현체를 생성하는 부분일 것이다.

 

 

컴포지트

하나의 객체가 다른 객체 목록의 행위를 조합한 것처럼 행동하게 만드려면 객체 집합을 단일 객체에 대한 임포스터로 구현해야 한다. 예를 들어 값의 증분을 저장하는 Transaction 클래스와 잔액을 얻어내는 Account 클래스가 있다고 하자.

Transaction Class
Transaction(Money value) {
    this.value = value;
}

Account Class
Transaction transactions[];
Money balance() {
    Money sum = Money.zero();
    for (int i = 0; i < transactions.length; i++) {
        sum = sum.plus(transactions[i].value);
    }
    return sum;
}

그리고 이제 고객이 여러 계좌를 가지고 있고, 전체 계좌의 잔액을 조회하는 기능을 추가한다고 하자. 이를 구현하는 명백한 방법은 OverallAccount를 만드는 것이다. 하지만 이는 분명 중복이다.

그렇기에 Account와 Balance가 동일한 인터페이스인 Holding(소유 재산)을 갖도록 하면, 조합을 통해 문제를 해결할 수 있다.

Holding Interface
interface Holding {
    Money balance();
}

Transaction Class
Money banlance() {
    return value;
} 

Account Class
Holding holdings[];
Money balance() {
    Money sum = Money.zero();
    for (int i = 0; i < holdings.length; i++) {
        sum = sum.plus(holdings[i].balance());
    }
    return sum;
}

 

수집 매개변수

여러 객체에 걸쳐 존재하는 오퍼레이션의 결과를 수집하려면 결과가 수집될 객체를 각 오퍼레이션의 매개변수로 추가해야 한다.

 

 

싱글톤

전역 변수를 제공하지 않는 언어에서 전역변수를 사용하고자 하지도 말라. 그 시간을 설계에 투자하라

 

 

[ 31. 리팩토링 ]

일반적으로 리팩토링은 어떤 상황에서도 프로그램의 의미론을 변경해서는 안된다.

하지만 TDD에서는 리팩토링이 조금 특이하게 사용된다. TDD의 관점에서 우리가 신경쓰는 부분은 현재 이미 통과한 테스트들 뿐이며, TDD에서 프로그램의 의미론은 테스트의 통과이다. 그렇기 때문에 TDD에서 상수를 변수로 바꾸는 것은 테스트를 그대로 통과시키므로 리팩토링이다.

그리고 이를 기반으로 하기 위해서는 충분한 테스트를 가지고 있어야 한다.

 

 

차이점 일치시키기

비슷해 보이는 두 코드 조각을 합치려면 두 코드가 닮아가게끔 단계적으로 수정해야 한다. 그리고 완전히 동일해졌을 때 합치면 된다.

이 리팩토링은 다음과 같은 작업에서 발생할 수 있다.

  • 반복문의 구조가 비슷하다. —> 이 둘을 동일하게 만들고 하나로 합친다.
  • 조건문에 의해 나눠지는 분기가 비슷하다. —> 이 둘을 동일하게 만들고 나서 조건문을 제거한다.
  • 두 클래스가 비슷하다. —> 이 둘을 동일하게 만들고 나서 하나를 제거한다.

간혹 차이점 일치시키기를 거꾸로 수행해야 할 수도 있다. 이 말은 변경 마지막 단계에서 어떤 모양새가 되어야 할지 생각한 다음 거꾸로 올라가는 것이다.

 

 

변화 격리하기

객체나 메소드의 일부만 바꾸려면 우선 바꿔야 할 부분을 격리해야 한다. 변화를 격리하기 위해서는 메소드 추출, 객체 추출, 메소드 객체 등의 방법이 있다.

바꿀 부분을 격리하고 나서 바꾸는 작업을 수행하면 작업을 되돌리기도 매우 수월하다.

 

 

메소드 추출하기

길고 복잡한 메소드를 읽기 쉽게 만드려면, 긴 메소드의 일부분을 별도의 메소드로 분리하면 된다.

복잡한 코드를 이해하고자 할 때, 메소드를 추출해내면 이해가 쉬워진다. 또한 비슷한 두 메소드에서 중복을 제거하기 위해 사용될 수도 있다.

 

 

메소드 인라인

너무 꼬여있거나 복잡한 제어 흐름을 단순화하려면 호출되는 메소드를 실제 메소드의 내용으로 교체하면 된다. 물론 이렇게 해서 코드가 더 보기 좋아지지 않을 수 있다.

메소드를 인라인할 수도 있고, 추상화 시킬 수도 있다는 사실은 중요하므로, 이리저리 바꾸어가며 사용하면 된다.

 

 

객체 기반의 기법

  • 인터페이스 추출
  • 클래스 추출
  • 메소드 옮기기
  • 매개변수 추가
  • 메소드 매개변수를 생성자 매개변수로 바꾸기

 

[ 32. TDD 마스터하기 ]

TDD를 각자의 습관에 통합시켜 나가는 과정에서 숙고해볼만한 몇 가지 질문을 던지고자 한다.

 

단계가 얼마나 커야 하나?

사실 이 질문에는 두 가지 질문이 숨어 있다.

  • 각 테스트가 다뤄야 할 범위는 얼마나 넓은가?
  • 리팩토링을 하면서 얼마나 많은 중간 단계를 거쳐야 하는가?

우리는 한 줄의 로직을 추가하고 약간의 리팩토링을 할 정도 크기의 테스트를 만들 수도 있고, 수백 줄의 로직과 많은 시간이 필요한 테스트를 만들 수도 있다. 하지만 결국 우리는 둘 다 할수 있어야 하며, 시간이 지남에 따라 TDD를 하는 개발자는 점점 작은 단계로 진행하는 경향이 나타난다.

리팩토링 초기에는 아주 작은 단계로 작업할 준비가 되어 있어야 한다. 그렇게 해서 많은 작업을 하다보면 점점 리팩토링을 덜 하게 될 것이고, 작은 단계는 건너 뛰게 될 것이다.

 

 

테스트할 필요가 없는 것은 무엇인가?

플립(Phlip)은 "두려움이 지루함으로 변할 때까지 테스트를 만들어라"라고 대답했다. 하지만 이것은 조언일 뿐이기에 스스로 대답을 찾아야 한다.

하지만 다른 사람이 만든 코드는 테스트하지 마라. 다른 사람이 만든 버그를 테스트 하다가, 해당 버그가 수정되면 테스트는 실패하는 등의 문제가 발생하기 때문이다.

 

 

좋은 테스트를 갖췄는지의 여부는 어떻게 알 수 있는가?

TDD란 테스트를 통해 좋은 설계를 향해 나아가는 과정이다. 다음은 설계에 문제가 있음을 알려주는 테스트의 속성들이다.

  • 긴 셋업코드: 객체가 너무 크다는 의미이므로 나뉠 필요가 있다.
  • 셋업 중복: 공통의 셋업 코드를 넣어 둘 공통의 장소를 찾기 힘들다면, 객체가 밀접하게 엉켜있다는 것이다.
  • 실행이 오래 걸리는 테스트: 실행 시간이 길다는 것은 작은 부분이 아니라는 것이므로, 설계 문제를 의미한다.
  • 깨지기 쉬운 테스트: 예상치 못하게 실패하는 테스트가 있다면, 이는 애플리케이션의 특정 부분이 이상한 방법으로 다른 부분에 영향을 준다는 것이므로 연결을 끊거나 합하여 영향력이 없도록 해야한다.

 

피드백(테스트)가 얼마나 필요한가?

우리는 자신의 경험과 숙고를 통해, 얼마나 많은 테스트를 작성할 지 결정해야 한다.

테스트를 얼마나 작성할 지 고려할만한 단위는 실패간 평균시간(MTBF, Mean Time Between Failure) 이다. 만약 우리의 시스템이 하루에 한번 오작동 난다면 MTBF는 24H 이다.

만약 시스템의 MTBF를 높게 잡고자 한다면 많은 정말 일어나지 않을 것 같은 조건도 나름대로 의미가 있다.

TDD에서 테스트에 대한 관점은 실용적이다. TDD에서 테스트는 깊이 신뢰할 수 있는 코드를 작성하기 위한 하나의 수단이다. 만약 어떤 구현에 대한 지식이 신뢰할 만 하다면 그에 대한 테스트를 작성하지 않을 수도 있다.

 

 

테스트를 지워야 할 때는 언제인가?

테스트가 많으면 좋지만 서로 겹치는 두 개의 테스트가 있다면 다음과 같은 두 가지 기준에 따라 처리하면 된다.

  • 자신감: 테스트를 삭제하여 자신감이 줄어들 것 같으면 절대 테스트를 지우지 말아야 한다.
  • 커뮤니케이션: 두 개의 테스트가 동일한 부분을 실행하더라도, 서로 다른 시나리오라면 남겨야 한다.

그 외에 별 부가적인 이득이 없는 중복된 테스트라면, 덜 유용한 것을 삭제하면 된다.

 

 

TDD는 누구를 위한 것인가?

모든 프로그래밍 방법은 어떤 가치 체계를 내포한다. 그 중에서 TDD는 더 나은 코드를 작성한다면 좀 더 성공할 것이라는 가정에 근거한다. TDD는 더 깔끔한 설계를 할 수 있도록, 그리고 더 많은 것을 배워감에 따라 설계를 개선할 수 있도록, 적절한 때 적절한 문제에 집중할 수 있도록 도와준다. 또한 TDD는 시간이 지남에 따라 코드에 대한 자신감을 더 쌓아갈 수 있게 해준다. 그리고 설계를 개선해 나감에 따라 점점 더 많은 설계 변경이 가능해진다. 즉, TDD로 개발하면 1년이 지난 후에 더 좋은 느낌을 갖게 된다.

 

 

 

관련 포스팅

  1. Test-Driven Development: By Example(테스트 주도 개발) 내용 정리 - 예시 (1)
  2. Test-Driven Development: By Example(테스트 주도 개발) 내용 정리 - 방법 (2)

 

 

반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG more
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함