TDD의 첫 번째 테스트에서 필요하다고 생각되는 객체를 만들고 있습니까?


15

나는 TDD를 처음 접했고 구현 코드 앞에 올 때 첫 번째 테스트를 만들 때 문제가 있습니다. 구현 코드에 대한 프레임 워크가 없으면 첫 번째 테스트를 자유롭게 작성할 수 있지만 원하는 Java / OO 방식으로 문제가 발생하는 것으로 보입니다.

예를 들어, Github ConwaysGameOfLifeExample 에서 내가 작성한 첫 번째 테스트 (rule1_zeroNeighbours)는 아직 구현되지 않은 GameOfLife 객체를 만들어 시작했습니다. 존재하지 않는 set 메소드, 존재하지 않는 단계 메소드, 존재하지 않는 get 메소드를 호출 한 다음 어설 션을 사용했습니다.

테스트를 더 작성하고 리팩토링하면 테스트가 발전했지만 원래는 다음과 같습니다.

@Test
public void rule1_zeroNeighbours()
{
    GameOfLife gameOfLife = new GameOfLife();
    gameOfLife.set(1, 1, true);
    gameOfLife.step();
    assertEquals(false, gameOfLife.get(1, 1));
}

이 초기 단계에서 첫 번째 테스트를 작성하기로 결정한 방식에 따라 구현 설계를 강요하면서 이상한 느낌이 들었습니다.

TDD를 이해하는 방식으로 괜찮습니까? 리팩토링을 통해 시간이 지남에 따라 테스트 및 구현이 진화했다는 점에서 TDD / XP 원칙을 따르는 것 같습니다. 따라서이 초기 디자인이 쓸모없는 것으로 판명되면 변경하기에 개방적이지만 이 방법으로 시작하여 솔루션.

사람들은 어떻게 TDD를 사용합니까? GameOfLife 오브젝트, 프리미티브 및 정적 메소드만으로 시작하여 리팩토링 반복을 더 많이 수행 할 수 있었지만 너무 많은 생각이 들었습니다.


5
TDD는 신중한 계획이나 신중한 디자인 패턴 선택을 대체하지 않습니다. 즉, 처음 몇 줄의 테스트를 만족시키기 위해 구현을 작성하기 전에 계획이 어리 석거나, 잘못된 패턴을 선택했거나 심지어 테스트가 요구하는 방식으로 클래스를 호출하는 것은 어색하거나 혼란 스러워요.
svidgen

답변:


9

이 초기 단계에서 첫 번째 테스트를 작성하기로 결정한 방식에 따라 구현 설계를 강요하면서 이상한 느낌이 들었습니다.

이것이 당신의 질문의 핵심 포인트라고 생각합니다. 이것이 바람직한 지 아닌지는 당신이 미리 설계해야한다는 codeninja의 아이디어에 의존하는지, 구현을 채우기 위해 TDD를 사용하는지, 또는 테스트에 관여해야한다는 durron의 아이디어에 달려 있는지에 달려 있습니다 디자인뿐만 아니라 구현도 추진합니다.

나는 당신이 선호하는 것 (또는 당신이 중간에 빠지는 곳)이 당신이 선호하는 것으로 스스로 발견해야 할 것이라고 생각합니다. 각 접근 방식의 장단점을 이해하는 것이 유용합니다. 아마도 많은 것이 있지만, 나는 주요한 것들이 있다고 말할 것입니다 :

프로 선행 디자인

  • 그러나 TDD가 설계를 추진하는 과정은 훌륭하지만 완벽하지는 않습니다. 구체적인 목적지를 염두에 두지 않은 TD는 때때로 막 다른 길을 잃을 수 있으며, 이러한 막 다른 길은 적어도 어디에서 끝내고 싶은지를 미리 생각하면 피할 수있었습니다. 이 블로그 기사 는 Roman Numerals kata의 예를 사용 하여이 논쟁을 제기하고 그것을 보여주기 위해 다소 훌륭한 최종 구현이 있습니다.

프로 테스트 운전 설계

  • 코드 클라이언트 (테스트)를 중심으로 구현을 구축하면 불필요한 테스트 사례를 작성하지 않는 한 YAGNI 준수가 거의 무료로 제공됩니다. 더 일반적으로 소비자가 사용하도록 설계된 API를 얻습니다.이 API는 궁극적으로 원하는 것입니다.

  • 코드를 작성하기 전에 많은 UML 다이어그램을 그린 다음 공백을 채우는 아이디어는 훌륭하지만 거의 현실적이지 않습니다. Steve McConnell의 코드 완성 (Code Complete)에서 디자인은 "악한 문제"로 유명합니다. 적어도 부분적으로 해결하지 않으면 완전히 이해할 수없는 문제입니다. 근본적인 문제 자체가 변화하는 요구 사항을 통해 변경 될 수 있다는 사실과 이것을 결합하십시오.이 디자인 모델은 약간의 희망을 느끼기 시작합니다. 테스트 운전을 통해 구현뿐만 아니라 설계시 한 번에 한 작업 분량 만 물을 수 있으며, 빨간색으로 녹색으로 변하는 수명 동안이 작업은 여전히 ​​최신 상태이며 관련성이 있음을 알고 있습니다.

durron이 말한 것처럼 특정 예제와 같이 가장 간단한 테스트를 작성하여 디자인을 이끌어 내고 가능한 최소한의 인터페이스를 사용하는 방법을 사용했다면 코드 스 니펫의 인터페이스보다 간단한 인터페이스로 시작할 수 있습니다. .


이 링크는 Ben이 잘 읽었습니다. 공유해 주셔서 감사합니다.
RubberDuck

1
@RubberDuck 천만에요! 나는 실제로 그것에 완전히 동의하지는 않지만, 그 견해를 주장하는 훌륭한 일을한다고 생각합니다.
Ben Aaronson

1
나도 확실하지 않지만 그 경우가 잘됩니다. 정답은 중간에 있다고 생각합니다. 계획이 있어야하지만 테스트가 어색하다고 생각되면 다시 디자인하십시오. 어쨌든 ... ++ 좋은 쇼 오래된 콩.
RubberDuck

17

먼저 테스트를 작성하려면 구현할 API설계 해야합니다. 테스트를 작성하여 전체 GameOfLife 오브젝트 를 작성하고 이를 사용하여 테스트를 구현 함으로써 이미 잘못된 발로 시작했습니다 .

JUnit 및 Mockito를 사용한 실제 단위 테스트에서 :

처음에는 거기에없는 것을 쓰는 것이 어색 할 수도 있습니다. 코딩 습관에 약간의 변화가 필요하지만 시간이 지나면 훌륭한 디자인 기회가 될 것입니다. 먼저 테스트를 작성하면 클라이언트가 사용하기 편리한 API를 작성할 수 있습니다. 테스트는 새로 태어난 API의 첫 번째 클라이언트입니다. 이것이 바로 TDD의 핵심입니다 : API 디자인.

테스트는 API를 디자인하려는 시도를 크게하지 않습니다. 모든 기능이 외부 GameOfLife클래스 내에 포함 된 상태 저장 시스템을 설정했습니다 .

이 응용 프로그램을 작성한다면 대신 내가 만들고 싶은 조각에 대해 생각할 것입니다. 예를 들어, Cell더 큰 응용 프로그램으로 이동하기 전에 클래스를 만들고 테스트를 작성할 수 있습니다 . Conway를 올바르게 구현하고 테스트하는 데 필요한 "모든 방향으로 무한한"데이터 구조에 대한 클래스를 작성해야합니다. 모든 것이 끝나면 main메서드 등 을 가진 전체 클래스를 작성하는 것에 대해 생각할 것 입니다.

"실패한 테스트 작성"단계를 쉽게 설명 할 수 있습니다. 그러나 원하는 방식으로 작동 하는 실패한 테스트 작성하는 것이 TDD의 핵심입니다.


1
셀을 고려하면 단지에 대한 래퍼 것 boolean, 것을 디자인은 확실히 성능이 악화 될 것입니다. 미래에 두 개 이상의 상태를 가진 다른 세포 오토마타로 확장 가능해야하지 않는 한?
user253751

2
@immibis 세부 사항에 문제가 있습니다. 셀 모음을 나타내는 클래스로 시작할 수 있습니다. 성능에 문제가있는 경우 나중에 셀 콜렉션을 나타내는 클래스로 셀 클래스 및 해당 테스트를 마이그레이션 / 병합 할 수도 있습니다.
Eric

@immibis 성능상의 이유로 라이브 이웃 수를 저장할 수 있습니다. 의 수는 셀의 이유로 착색을 위해, 살아 있었다 틱 ...
Blorgbeard가 부족

@immibis 조기 최적화는 악하다 ... 게다가 원시적 인 강박 관념을 피하는 것은 얼마나 많은 주를 지원하든 양질의 코드를 작성하는 좋은 방법이다. jamesshore.com/Blog/PrimitiveObsession.html
Paul

0

이것에 대해 다른 생각의 학교가 있습니다.

일부는 말합니다 : 컴파일하지 않은 테스트는 오류입니다-가능한 가장 작은 생산 코드를 작성하십시오.

어떤 말 : 개미를 빨아 먹는지 먼저 검사를 작성하고 누락 된 클래스 / 메소드를 작성해도 괜찮습니다.

첫 번째 접근 방식을 사용하면 실제로 빨강-녹색 리 팩터주기에 있습니다. 두 번째로 당신이 달성하고자하는 것을 조금 더 넓게 볼 수 있습니다.

당신이 일하는 방식을 선택하는 것은 당신에게 달려 있습니다. IMHO 두 가지 접근 방식이 모두 유효합니다.


0

"함께 해킹"하는 방식으로 무언가를 구현하더라도 전체 프로그램에 포함될 클래스와 단계를 계속 생각합니다. 그래서 당신은 이것을 통해 생각하고 이러한 디자인 생각을 테스트로 먼저 작성했습니다-훌륭합니다!

이제 두 가지 구현을 반복하여이 초기 테스트를 수행 한 다음 테스트를 추가하여 디자인을 개선하고 확장하십시오.

도움이 될만한 것은 Cucumber 또는 이와 유사한 것을 사용 하여 테스트를 작성하는 것입니다.


0

테스트 작성을 시작하기 전에 시스템 설계 방법에 대해 생각해야합니다. 디자인 단계에서 상당한 시간을 소비해야합니다. 당신이 그것을했다면, 당신은 TDD에 대한 혼란을 얻지 못할 것입니다.

TDD는 단지 개발 접근 방식 링크입니다. TDD
1. 테스트 추가
2. 모든 테스트를 실행하고 새 테스트가 실패하는지 확인하십시오.
3. 코드 작성
4. 테스트 실행
5. 리 팩터 코드
6. 반복

TDD를 사용하면 소프트웨어 개발을 시작하기 전에 계획 한 모든 필수 기능을 다룰 수 있습니다. 링크 : 장점


0

그런 이유로 Java 또는 C #으로 작성된 시스템 레벨 테스트를 좋아하지 않습니다 . c #에 대한 SpecFlow 또는 java에 대한 Cucumber 기반 테스트 프레임 워크 중 하나 (JBehave)를보십시오. 그러면 테스트가 다음과 같이 보일 수 있습니다.

여기에 이미지 설명을 입력하십시오

또한 모든 시스템 테스트를 변경하지 않고도 객체 디자인을 변경할 수 있습니다.

(“정상적인”단위 테스트는 단일 클래스를 테스트 할 때 좋습니다.)

Java 용 BDD 프레임 워크의 차이점은 무엇입니까?

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