테스트를 시작하기 위해 디자인이 필요한 경우 TDD가 좋은 디자인을 얻는 데 어떻게 도움이되는지 모르겠습니다.


50

TDD를 중심으로 머리를 감싸려고합니다. 특히 개발 부분입니다. 몇 가지 책을 보았지만 주로 찾은 책은 주로 테스트 부분-NUnit의 역사, 테스트가 좋은 이유, 빨강 / 녹색 / 리 팩터 및 문자열 계산기를 만드는 방법을 다룹니다.

좋은 점이지만 TDD가 아니라 "단지"단위 테스트입니다. 특히, 테스트를 시작하기 위해 디자인이 필요한 경우 TDD가 어떻게 좋은 디자인을 얻는 지 이해하지 못합니다.

설명하기 위해 다음 세 가지 요구 사항을 상상해보십시오.

  • 카탈로그에는 제품 목록이 있어야합니다.
  • 카탈로그는 사용자가 본 제품을 기억해야합니다
  • 사용자는 제품을 검색 할 수 있어야합니다

이 시점에서 많은 책들이 마술 토끼를 모자에서 꺼내어 "Testing the ProductService"로 뛰어 들지만, 처음에는 ProductService가 있다는 결론을 내린 방법에 대해서는 설명하지 않습니다. 그것이 제가 이해하려고하는 TDD의 "개발"부분입니다.

기존 디자인이 필요하지만 엔터티 서비스 외부의 항목 (즉, 제품이 있으므로 ProductService가 있어야 함)을 찾을 수 없습니다 (예 : 두 번째 요구 사항을 충족하려면 사용자, 그러나 어디에서 상기 기능을 상기시킬 것인가? 검색은 ProductService의 기능입니까 아니면 별도의 SearchService입니까? 어떻게 선택해야하는지 어떻게 알 수 있습니까?)

SOLID 에 따르면 UserService가 필요하지만 TDD가없는 시스템을 설계하면 수많은 단일 메소드 서비스가 생길 수 있습니다. TDD가 처음에 내 디자인을 발견하게하려는 것이 아닙니까?

저는 .net 개발자이지만 Java 리소스도 작동합니다. 실제 업무용 응용 프로그램을 다루는 실제 샘플 응용 프로그램이나 책이없는 것 같습니다. 누군가가 TDD를 사용하여 디자인을 만드는 과정을 보여주는 명확한 예를 제공 할 수 있습니까?


2
TDD는 전체 개발 방법론의 일부일뿐입니다. 물론 모든 것을한데 모으려면 어떤 종류의 디자인 (선불 또는 더 나은 진화)을 사용해야합니다.
Euphoric

3
@ gnat : TDD 서적이 디자인 프로세스를 더 명확하게하지 않는 이유에 대한 질문입니다.
Robert Harvey

4
@ gnat : 그것은 내 편집이 아니라 편집이었습니다. :) 질문의 제목과 본문에 대한 나의 변화를보십시오.
Robert Harvey

9
Robert C. Martin의 작품을 읽었거나 그의 비디오 중 하나를 보았을 때, 그는 종종 디자인을 염두에두고 있지만 결혼하지 않은 것을 볼 수 있습니다. 그는 올바른 디자인에 대한 선입견이 그의 테스트에서 나올 것이라고 믿지만 그것을 강요하지는 않는다. 그리고 결국, 그 디자인은 때때로, 때로는 그렇지 않습니다. 내 요점은 당신의 자신의 사전 경험이 당신을 안내 할 것이지만, 시험이 당신을 이끌 것입니다. 테스트는 디자인을 개발하거나 디버깅 할 수 있어야합니다.
Anthony Pegram

3
테스트에 관한 것이 아니라 디자인에 관한 것입니다. 디자인을 검증하는 데 도움이되는 것만으로는 실제로 디자인에 도움이되지 않습니다. 그러나! @ # $ ing 테스트가 아닙니까?
Erik Reppen

답변:


17

TDD의 아이디어는 테스트로 시작하여 그로부터 작업하는 것입니다. 따라서 "카탈로그에 제품 목록이 있어야 함"의 예를 들어 보면 "카탈로그의 제품 확인"테스트가있는 것으로 볼 수 있으므로 이것이 첫 번째 테스트입니다. 이제 카탈로그는 무엇입니까? 제품은 무엇입니까? 이것들은 다음 조각이며 아이디어는 첫 번째 테스트를 통과하여 생성되는 ProductService와 같은 비트와 조각을 모으는 것입니다.

TDD의 아이디어는 테스트로 시작한 다음 테스트를 첫 번째 포인트로 통과시키는 코드를 작성하는 것입니다. 단위 테스트는이 부분의 일부이지만 테스트로 시작한 다음 코드를 작성하여 코드가 없기 때문에이 시점에서 사각 지대가 없도록 형성된 전체 그림을 보지 않습니다.


슬라이드 20-22가 핵심적인 테스트 중심 개발 튜토리얼 . 아이디어는 결과적으로 기능이 무엇을해야하는지 알고 테스트를 작성한 다음 솔루션을 구축하는 것입니다. 디자인 부분은 필요한 것이 무엇인지, 그렇지 않은지에 따라 달라집니다. 핵심은 프로젝트에 늦게 소개하지 않고 처음부터 TDD를 사용하는 것입니다. 테스트를 먼저 시작하면 도움이 될 수 있으며 의미가 있습니다. 나중에 테스트를 추가하려고 시도하면 연기되거나 지연 될 수 있습니다. 이후 슬라이드도 유용 할 수 있습니다.


TDD의 주요 이점은 테스트를 시작하여 처음에 설계에 구속되지 않는다는 것입니다. 따라서 아이디어는 테스트를 빌드하고 해당 테스트를 개발 방법론으로 통과시키는 코드를 작성하는 것입니다. 큰 디자인까지 전면 이 결국 덜 민첩로 구축되는 시스템을 만드는 장소로 물건을 잠금의 아이디어를 제공으로 문제가 발생할 수 있습니다.


Robert Harvey는 답변에 진술 할 가치가있는 의견에 이것을 추가했습니다.

불행히도 이것이 TDD에 대한 일반적인 오해라고 생각합니다. 단위 테스트를 작성하고 통과시켜 소프트웨어 아키텍처를 성장시킬 수는 없습니다. 단위 테스트를 작성하는 것은 디자인에 영향을 미칠 않지만, 그것은하지 않습니다 만드는 디자인. 그렇게해야합니다.


31
@MichaelStum : 불행히도 이것이 TDD에 대한 일반적인 오해라고 생각합니다. 단위 테스트를 작성하고 통과시켜 소프트웨어 아키텍처를 성장시킬 수는 없습니다. 단위 테스트를 작성하는 것은 디자인에 영향을 미칠 않지만, 그것은하지 않습니다 만드는 디자인. 당신은 그렇게해야합니다.
Robert Harvey

4
@RobertHarvey, JimmyHoffa : 귀하의 의견을 100 회 투표 할 수 있다면,하겠습니다!
Doc Brown

9
@Robert Harvey :이 일반적인 오해에 대해 글을 써서 다행입니다. 너무 자주 듣고 모든 종류의 단위 테스트를 작성해야하며 디자인이 자연스럽게 "일어납니다". 그리고 디자인이 나쁜 경우 충분한 단위 테스트를 작성하지 않았기 때문입니다. 테스트는 디자인 요구 사항을 지정하고 확인하는 도구이지만 디자인을 직접 "수행해야"한다는 데 동의합니다. 전적으로 동의합니다.
조르지오

4
@Giorgo, RobertHarvey : 나에게서 RobertHarvey까지 +1000. 불행히도, 그 오해는 일부 "전문가"TDD / 애자일 전문가들이 그것을 믿는 것으로 충분히 흔합니다. 예를 들어, 도메인 지식이나 분석없이 TDD에서 스도쿠 솔버를 "진화"할 수 있다고 가정합니다 . Ron Jeffries가 TDD의 한계에 대한 후속 조치를 게시했는지 또는 왜 결론이나 교훈을 얻지 않고 갑자기 실험을 중단했는지 설명했는지 궁금합니다.
Andres F.

3
@Andres F : 스도쿠에 대한 이야기를 알고 있으며, 그것이 매우 흥미 롭다고 생각합니다. 일부 개발자는 도구 (예 : TDD 또는 SCRUM)가 도메인 지식과 자체 노력을 대체 할 수 있다고 생각하는 실수를 저지르고 있으며, 특정 방법을 기계적으로 적용함으로써 좋은 소프트웨어가 마 법적으로 "창출"될 것으로 기대합니다. 그들은 종종 분석과 디자인에 너무 많은 시간을 소비하지 않고 직접 무언가를 코딩하는 것을 선호하는 사람들입니다. 그들에게는 특정한 방법론을 따르는 것이 적절한 디자인을하지 않는 것에 대한 알리바이입니다. 그러나 이것은 IMHO가 TDD의 오용입니다.
Giorgio

8

그 가치에 대해 TDD는 TDD를 하지 않는 것보다 최고의 디자인을 더 빨리 만들 수 있도록 도와줍니다 . 나는 그것이 있거나없는 최고의 디자인에 올 것입니다. 그러나 그 생각을하고 코드에서 몇 가지 찌르기를하는 데 드는 시간은 대신 테스트를 작성하는 데 소비되었습니다. 그리고 더 적은 시간입니다. 나를 위해. 모두를위한 것은 아닙니다. 그리고 같은 시간이 걸리더라도 일련의 테스트가 필요하므로 리팩토링이 더 안전하여 더 나은 코드로 연결됩니다.

어떻게합니까?

먼저 모든 클래스를 클라이언트 코드에 대한 서비스로 생각하도록 장려합니다. 더 나은 코드는 코드 자체의 모양에 대해 걱정하기보다는 호출 코드가 API를 사용하기를 원하는 방식에 대한 생각에서 비롯됩니다.

둘째, 너무 많은 순환 적 복잡성을 하나의 방법으로 쓰는 것을 멈추고 생각합니다. 방법을 통한 각 추가 경로는 수행해야 할 테스트 수를 두 배로 늘리는 경향이 있습니다. 엄청나게 게으름은 너무 많은 논리를 추가 한 후 하나의 조건을 추가하기 위해 16 가지 테스트를 작성해야한다는 것을 나타냅니다. 이제 일부를 다른 메소드 / 클래스로 가져 와서 별도로 테스트해야합니다.

정말 간단합니다. 마법의 디자인 도구가 아닙니다.


6

TDD 주위에 머리를 감 으려고 노력 중입니다 ... 설명하기 위해 다음 세 가지 요구 사항을 상상해보십시오.

  • 카탈로그에는 제품 목록이 있어야합니다.
  • 카탈로그는 사용자가 본 제품을 기억해야합니다

이러한 요구 사항은 인간의 관점에서 재조정되어야합니다. 사용자가 이전에 본 제품을 누가 알고 싶어합니까? 사용자? 영업 사원?

  • 사용자는 제품을 검색 할 수 있어야합니다

어떻게? 이름으로? 브랜드별로? 테스트 중심 개발의 첫 단계는 다음과 같이 테스트를 정의하는 것입니다.

browse to http://ourcompany.com
enter "cookie" in the product search box
page should show "chocolate-chip cookies" and "oatmeal cookies"

>

이 시점에서 많은 책들이 마술 토끼를 모자에서 꺼내어 "Testing the ProductService"로 뛰어 들지만, 처음에는 ProductService가 있다는 결론을 내린 방법에 대해서는 설명하지 않습니다.

이것이 유일한 요구 사항이라면 확실히 ProductService를 만들지 않을 것입니다. 정적 제품 목록으로 매우 간단한 웹 페이지를 만들 수 있습니다. 제품 추가 및 삭제 요구 사항에 도달 할 때까지 완벽하게 작동합니다. 이 시점에서 관계형 데이터베이스와 ORM을 사용하는 것이 가장 간단하다고 판단하고 단일 테이블에 매핑 된 Product 클래스를 만들 수 있습니다. 여전히 ProductService가 없습니다. 필요할 때 언제 필요한지 ProductService와 같은 클래스가 작성됩니다. 동일한 쿼리 또는 업데이트를 수행해야하는 웹 요청이 여러 개있을 수 있습니다. 그런 다음 코드 복제를 방지하기 위해 ProductService 클래스가 작성됩니다.

요약하면 TDD는 코드를 작성합니다. 구현을 선택할 때 디자인이 발생하고 코드를 클래스로 리팩토링하여 중복 및 제어 종속성을 제거합니다. 코드를 추가 할 때 코드 SOLID를 유지하려면 새 클래스를 작성해야합니다. 그러나 Product 클래스와 ProductService 클래스가 필요하다는 것을 미리 결정할 필요는 없습니다. Product 클래스만으로도 인생은 완벽하게 훌륭하다는 것을 알 수 있습니다.


그래, ProductService그럼 그러나 TDD는 데이터베이스와 ORM이 필요하다고 어떻게 말했습니까?
Robert Harvey

4
@ 로버트 :하지 않았다. 요구 사항을 충족시키는 가장 효과적인 방법에 대한 나의 판단에 근거한 설계 결정입니다. 그러나 결정은 바뀔 수 있습니다.
kevin cline

1
좋은 디자인은 어떤 임의의 프로세스의 부작용으로 만들어지지 않을 것입니다. IMO (테스트 우선 TDD) 인 IMO는 작업을 수행하고 프레임을 구성 할 시스템 또는 모델을 보유하는 것은 나쁜 부작용으로 인해 사람들이 예기치 않게 물리지 않도록 보장하는 무언가로 판매함으로써 이해 상충을 일으 킵니다. 처음에는 발생해서는 안되는 코드. 디자인에는 반성, 인식 및 예측이 필요합니다. 당신은 나무에서 자동으로 발견 된 증상을 잘라내는 것을 배우지 않습니다. 먼저 악의적 인 돌연변이 가지를 피하는 방법을 알아 냄으로써 그것들을 배웁니다.
Erik Reppen

테스트는 '제품을 추가; 컴퓨터를 재부팅하고 시스템을 다시 시작하십시오. 추가 된 제품은 여전히 ​​보입니다. ' 어떤 종류의 데이터베이스가 필요한 곳을 보여줍니다 (그러나 여전히 플랫 파일 또는 XML 일 수 있음).
yatima2975

3

다른 사람들은 동의하지 않을 수도 있지만, 나에게 많은 새로운 방법론은 개발자가 습관이나 개인적인 자부심으로 구식 방법론에서 설명한 대부분의 작업을 개발자가 수행한다는 가정에 의존합니다. 그들에게 작업이 포함되어 있으며, 작업은 깨끗한 언어 또는 다소 지저분한 언어의 깨끗한 부분으로 캡슐화되어 있으므로 모든 테스트 비즈니스를 수행 할 수 있습니다.

과거에 이것을 경험 한 몇 가지 예 :

  • 많은 스펙 작업 계약자를 가지고 팀이 민첩하고 테스트 우선이라고 말합니다. 그들은 종종 사양 작업 이외의 습관이 없으며 프로젝트를 완료하기에 오래 지속되는 한 작업의 품질에 대해 걱정하지 않습니다.

  • 새로운 테스트를 먼저 시도하고 수행하십시오. 다양한 접근 방식과 인터페이스가 잘못되어 테스트를 추출하는 데 많은 시간을 소비하십시오.

  • 낮은 수준의 코드를 작성하고 적용 범위가 부족하여 엉망이되거나 묶는 기본 동작을 조롱 할 수 없기 때문에 많은 가치가없는 많은 테스트를 작성하십시오.

  • 디스크 하위 시스템이나 tcpip 레벨 통신 인터페이스와 같이 테스트 할 수없는 여러 가지 비트를 먼저 작성하지 않고 테스트 가능한 기능을 추가 할 시간이 충분하지 않은 상황입니다.

당신이 TDD를하고 있고 당신을 위해 일하고 있다면, 당신에게 좋지만, 단순히 가치를 추가하지 않는 많은 일 (전체 작업 또는 프로젝트 단계)이 있습니다.

귀하의 예제는 아직 설계를하고 있지 않은 것처럼 들리므로 아키텍처 대화가 필요하거나 프로토 타이핑 중입니다. 내 의견으로는 먼저 그 중 일부를 통과해야합니다.


1

나는 TDD가 시스템 의 세부적인 디자인, 즉 API와 객체 모델에 매우 귀중한 접근법이라고 확신한다 . 그러나 TDD를 사용하기 시작하는 프로젝트에서 요점을 찾으려면 디자인의 큰 그림이 어떤 방식으로 이미 모델링되어 있어야하고 아키텍처의 큰 그림이 이미 어떤 방식으로 모델링되어 있어야합니다. 로버트 마틴 (Robert Martin)은 @ user414076의 말을 디자인 아이디어를 염두에두고 결혼하지는 않았다. 바로 그거죠. 결론-TDD는 진행중인 유일한 디자인 활동이 아니라 디자인의 세부 사항이 완성되는 방식입니다. TDD에는 다른 설계 활동이 선행되어야하며 전체 설계가 생성되고 발전되는 방식을 다루는 전체 접근 방식 (예 : 애자일)에 적합해야합니다.

참고로-실용적이고 현실적인 예를 제공하는 주제에 대해 추천하는 두 권의 책 :

테스트 가이드에 따라 성장하는 객체 지향 소프트웨어 -전체 프로젝트 예제를 설명하고 제공합니다. 이 책은 테스트가 아니라 디자인에 관한 책 입니다. 테스트는 디자인 활동 중 예상되는 동작을 지정하는 수단으로 사용됩니다.

테스트 중심 개발 실용 가이드 -비록 작지만 완전한 앱을 개발하는 단계를 천천히 그리고 단계별로 안내 합니다.


0

TTD는 성공이 아닌 테스트 실패로 설계 발견을 주도합니다. 따라서 미지의 요소가 노출 될 때 미지의 요소를 테스트하고 반복적으로 다시 테스트 할 수 있습니다. 코드 작성 / 해제 후 개조

예를 들어, 입력이 몇 가지 다른 형식 일 수 있지만 모든 것이 아직 알려진 것은 아니라는 요구 사항이있을 수 있습니다. 먼저 적절한 출력이 제공되어 공급되는 검증 테스트 작성합니다 TDD를 사용하여 모든 입력 형식을. 분명히이 테스트는 실패하므로 알려진 형식을 처리하고 다시 테스트하는 코드를 작성하십시오. 알 수없는 형식은 요구 사항 수집을 통해 노출 되므로 코드를 작성 하기 전에 새로운 테스트가 작성 되므로 실패해야합니다. 그런 다음 새 형식을 지원하기 위해 새 코드가 작성되고 모든 테스트가 다시 실행되어 회귀 가능성이 줄어 듭니다.

또한 장치 고장을 "깨진"코드 대신 "완료되지 않은"코드로 생각하면 도움이됩니다. TDD는 완료되지 않은 장치 (예상 실패)를 허용하지만 깨진 장치 (예기치 않은 실패)의 발생을 줄입니다.


1
나는 이것이 유효한 워크 플로우라는 데 동의하지만 실제로 그러한 워크 플로우에서 고급 아키텍처가 어떻게 나타날 수 있는지 설명하지는 않습니다.
Robert Harvey

1
MVC 패턴과 같은 고급 아키텍처는 TDD만으로는 등장하지 않을 것입니다. 그러나 TDD에서 나타날 수있는 것은 쉽게 테스트 할 수 있도록 설계된 코드이며 이는 자체적으로 설계 고려 사항입니다.
다니엘 페레이라

0

질문에는 다음과 같이 명시되어 있습니다.

... 많은 책들이 마술 토끼를 모자에서 꺼내어 "Testing the ProductService"로 뛰어 들지만, 처음에는 ProductService가 있다는 결론에 도달 한 방법을 설명하지 않습니다.

그들은이 제품을 어떻게 테스트 할 것인지 생각함으로써 결론에 도달했습니다. "어떤 종류의 제품입니까?" "우리는 서비스를 만들 수 있습니다." "좋아, 그런 서비스에 대한 테스트를 작성하자"


0

기능은 많은 디자인을 가질 수 있으며 TDD는 어느 것이 가장 적합한지를 완전히 알려주지는 않습니다. 또한 테스트를 통해 더 많은 모듈 코드를 작성하는 데 도움이된다면 프로덕션 현실이 아니라 테스트 요구 사항에 맞는 모듈을 빌드 할 수도 있습니다. 그래서 당신은 당신이 가고있는 곳과 상황이 전체 그림에 어떻게 맞아야 하는지를 이해해야합니다. 달리 말하면 기능 및 비 기능 요구 사항이 있으며 마지막 요구 사항을 잊지 마십시오.

디자인에 대해서는 Robert C. Martin의 책 (Agile Development)뿐만 아니라 Martin Fowler의 엔터프라이즈 응용 프로그램 아키텍처 패턴 및 도메인 드라이버 디자인도 참조하십시오. 후자는 특히 요구 사항에서 엔티티와 관계를 추출하는 데 매우 체계적입니다.

그런 다음 해당 엔티티를 관리하는 방법에 대해 사용 가능한 옵션에 대해 잘 알고 있으면 TDD 접근 방식을 제공 할 수 있습니다.


0

TDD가 처음에 내 디자인을 발견하게하려는 것이 아닙니까?

아니.

먼저 설계하지 않은 것을 어떻게 테스트 할 수 있습니까?

설명하기 위해 다음 세 가지 요구 사항을 상상해보십시오.

  • 카탈로그에는 제품 목록이 있어야합니다.
  • 카탈로그는 사용자가 본 제품을 기억해야합니다
  • 사용자는 제품을 검색 할 수 있어야합니다

이것들은 요구 사항이 아니며 데이터의 정의입니다. 소프트웨어의 비즈니스가 무엇인지 모르겠지만 분석가가 그렇게 말하는 것은 아닙니다.

시스템의 변형이 무엇인지 알아야합니다.

요구 사항은 다음과 같습니다.

  • 이 제품의 재고가 충분한 경우 고객이 특정 수량의 제품을 주문할 수 있습니다.

따라서 이것이 유일한 요구 사항이라면 다음과 같은 수업이있을 수 있습니다.

public class Product {

  private int quantity;

  public Product(int initialQuantity) {
    this.quantity = initialQuantity;
  }

  public void order(int quantity) {
    // To be implemented.
  }

}

그런 다음 TDD를 사용하여 order () 메소드를 구현하기 전에 테스트 케이스를 작성합니다.

public void ProductTest() {

    public void testCorrectOrder() {

        Product p = new Product(10);
        p.order(3);
        p.order(4);

    }

    @Expect(ProductOutOfStockException)
    public void testIncorrectOrder() {

        Product p = new Product(10);
        p.order(7);
        p.order(4);

    }

}

따라서 두 번째 테스트가 실패하면 order () 메소드를 원하는 방식으로 구현할 수 있습니다.


0

당신은 TDD가 주어진 디자인을 잘 구현할 수 있다고 확신 합니다. 디자인 프로세스에 도움이되지 않습니다.


그러나 작업 코드를 위반하지 않고 설계를 개선 할 수있는 안전망을 제공합니다. 이것은 대부분의 사람들이 건너 뛰는 리팩토링입니다.
Adrian Schneider

-3

TDD는 많은 도움이되지만 소프트웨어 개발에는 중요한 부분이 있습니다. 개발자는 작성중인 코드들어야합니다 . 리팩토링은 TDD주기에서 세 번째 부분입니다. 이것은 개발자가 다음 빨간색 테스트로 가기 전에 집중하고 생각해야하는 주요 단계입니다. 중복이 있습니까? SOLID 원칙이 적용됩니까? 높은 응집력과 낮은 결합은 어떻습니까? 이름은 어떻습니까? 테스트에서 나오는 코드를 자세히 살펴보고 변경하고 다시 디자인해야하는 것이 있는지 확인하십시오. 코드와 코드에 의문을 제기하면 어떻게 설계되고 싶은지 알 수 있습니다. 나는 보통 여러 테스트 세트를 작성하고, 그 목록을 검사하고 첫 번째 단순한 디자인을 만듭니다. "최종"일 필요는 없습니다. 일반적으로 새로운 테스트를 추가 할 때 변경되므로 변경되지 않습니다. 그것이 디자인이 오는 곳입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.