1 / 63

Software development #2: Test-Driven Development

Combacsa’s SPARCS Web Seminar. Software development #2: Test-Driven Development. Test-Driven Development. Test-Driven Development. Agile Family (of course!) Test Code 작성으로부터 프로그램 개발이 진행되게 하는 방법론 . Two major philosophy 코딩을 시작하기에 앞서 , 실패하는 , 자동화된 테스트 코드 부터 작성하라 . 중복 을 제거 하라.

Télécharger la présentation

Software development #2: Test-Driven Development

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Combacsa’s SPARCS Web Seminar Software development #2:Test-Driven Development

  2. Test-Driven Development

  3. Test-Driven Development • Agile Family (of course!) • Test Code 작성으로부터프로그램 개발이 진행되게 하는 방법론. • Two major philosophy • 코딩을 시작하기에 앞서,실패하는, 자동화된 테스트 코드부터 작성하라. • 중복을 제거하라.

  4. Test Code 의 역할? • Test Code 는 보조 수단이다 • 프로그램 개발에 필수적인 요소 • 문서 • 설계 • 개발 실력 • 디버깅 능력 • Test Code 는 조금 더 안심할 수 있도록 할 뿐 • 프로그램 개발의 필수 요소라고 볼 수 없다

  5. TDD 에서 Test Code 의 역할! • Test Code 는 필수적이다! • Working Software 의 정의 • “올바르게” 동작하는 프로그램 • “올바르다” 의 정의는 어떻게 내리는가? • 그때 그때 실행해 보면서? • No, 확고하게 설계한 Test Code 를 실행해서! • Test Code 작성만으로도 대형 프로젝트가 얼마든지 진행될 수 있다!

  6. Test 는 프로그램이당연히 통과해야 하는 것 • Test Code 작성은 프로그램 개발의 보조수단일 뿐이다

  7. TDD Rhythm in 5 Steps • Add a new TEST • Run all TESTs, and check there is a FAILURE • Slightly modify CODE • Run all TESTs, and check everything SUCCESS • Eliminate DUPLICATION by REFACTORING

  8. TDD 에 따른 프로젝트의 삶 • 고객과 함께 TO-DO List를 작성한다 • 리스트에서 할 일 하나을 고른다 • TDD Rhythm을 타면서 그 일을 처리한다 • 중간에 새로운 일이 생겨도 지금 처리중인 일에만집중하고, 새로 생긴 일은 까먹지 않도록단지 TO-DO List 에 올리기만 한다 • TO-DO List 가 빌 때까지 반복한다 • 프로그램 개발이 끝난다

  9. TO-DO LIST 할일 1 할일 2 할일 n … 할일 i TEST still SUCCESS TEST Code for 할일 i Refactored Code for 할일 i TEST SUCCESS TEST Failure Code for 할일 i

  10. TDD Terminology • Red bar period • Period when one or more tests fail • 테스트 중 하나라도 통과하지 못한다 • Green bar period • Period when entire tests success • 모든 테스트를 통과한다 • 개발 진행 = 새로운 빨간막대 파란막대

  11. Let’s see how it really works.

  12. 제한점 • 어디까지나 TDD 를 “보여주기” 위한 것 • TDD 를 진행하면서 일어날 수 있는 다양한 상황들을 위한 작위적인 예제임을 잊지 말자 • JUnit Framework 를 사용하여 Java 로 코딩 • Java 를 모르는 사람은 따라해보긴 힘들겠다 • Java 를 알면 알아서 프로젝트 생성 / 파일 추가 잘 하고 따라해보길 바람 • 귀찮아서 Eclipse 스크린샷은 안 뜨겠음

  13. Kent Beck’s Example • Project Bank Account • 은행의 사용자 계좌 관리 프로그램을 개발하자 • 고객은 다음과 같은 사항을 요구한다 • 서로 다른 통화간에 덧셈이 가능해야 함 • 계좌에 있는 돈을 특정 배로 늘릴 수 있어야 함 • Blah Blah Yada Yada … • 첫단계 • TO-DO List 부터 작성하자.

  14. TO-DO List 의 작성법 • 각각의 기능을 최대한 분해할 것 • 새로운 기능은 최소한의 Test 로 검증가능해야! • 때때로 TO-DO List 에서 제거할 일도 있다 • 다른 일을 처리하면서 자연스레 해결되는 경우.

  15. TO-DO List 작성의 실제 • 고객 요구 조건 (Recall) • 서로 다른 통화간에 덧셈이 가능해야 함 • 계좌에 있는 돈을 특정 배로 늘릴 수 있어야 함 • 두 계좌에 있는 돈이 동일함을 확인해야 함 • 기능만 뽑아내어 다시 써보자! • $5 + 10YEN = $6 (환율이 1:10 일 때) • $5 x 2 = $10 • $5 = $5 (서로 다른 계좌)

  16. 할일 고르기 • 원칙 • 다른 일보다 먼저 진행될 수 있는 것부터 • 다른 일보다 먼저 진행되어야 하는 것부터 • 좀더 쉽고 단순한 일부터 • TODO List Recall • $5 + 10YEN = $6 (환율이 1:10 일 때) • $5 x 2 = $10  한 계좌에 대한 것. 너로 정했다 • $5 = $5 (서로 다른 계좌)

  17. Test Code 설계 • Test Code 를 작성하며 결정되는 것들 • 함수 / 클래스의 이름과 파라메터 • 각 함수 / 클래스의 예상되는 동작 public void testMultiplication() { Dollar five = new Dollar(5); five.times(2); assertEquals(10, five.amount); }

  18. Test 실행 • 결과 확인 • 테스트 실패 : 컴파일조차 되지 않는다. • Dollar 라는 클래스가 정의되지 않음 • 실패에 대한 대처법 • 원인을 파악하고 가장 간단한 것부터 해결한다 • 지금은 Dollar 클래스를 정의하면 충분하겠다 • times 메소드와 amount 필드가 있어야겠다 • 어떻게든 이 테스트 코드를 통과시킬 수 없다면 • 다른 할일부터 해결하는 것이 나을지도 모른다

  19. Dollar 클래스 설계 Public class Dollar { int amount; public Dollar(int amount) { } void times(int multiplier) { } }

  20. Test 실행 • 결과 확인 • assertEquals(10, five.amount); • 결과가 0 이 나오고 있다 • assertEquals(A, B) 메소드 • A 의 값과 B 의 값이 일치할 때 통과하고,일치하지 않을 때 실패하는 메소드이다 • five 객체의 amount 변수의 값이 10이 아니어서 통과하지 못한 것이다

  21. 상념에 대한 적절한 대처 • 상념 1 : amount 멤버 변수는 개인 정보이니private 로 지정되었어야 하지 않나? • 대처 1 : TODO 리스트에 다음을 추가한다 • Amount 를 private 로 만들기 • 상념 2 : 실수 연산일텐데, 반올림 처리는? • 대처 2 : TODO 리스트에 다음을 추가한다 • Money 반올림? • 상념에 방해받지 말자. TODO List 가 기억!

  22. Test 결과에 대한 적절한 대처 • 한번의 코딩으로 초록 막대를 보지 못함을 슬퍼할 이유는 전혀 없다 • 결국은 초록 막대를 볼 것임을 우리는 안다 • 가장 단순한 해결책을 찾는다 • five 객체의 amount 변수의 값이 10이 아니어서 통과하지 못한 것이라고 했었다 • 결론 : 객체의 amount 변수의 값이 10이어야!

  23. 가장 간단한 코드 수정 Public class Dollar { int amount = 10; public Dollar(int amount) { } void times(int multiplier) { } }

  24. Test 실행 • 결과 • 모든 테스트가 성공한다 • 의의 • 오직 테스트를 통과시키기 위한 목적의 코딩. • 이런 코드는 사실 죄악이다.그리고 그런 죄악을 저지르자. 왜? • 프로그램 개발 = 테스트 코드를 만들고그 테스트를 통과시켜 초록 막대를 보는 거니까! • 그리고 죄악은 수습하면 그만이다.

  25. 죄악의 수습 • 죄악을 저지르는 이유 • 테스트 케이스에 대해 빨간 막대를 유지하면 • 심리적인 불안감이 조성된다 • 기분이 나쁘고 언짢다 • 따라서 최대한 빨리 초록 막대를 보는 게 낫다 • 죄악을 수습하는 방법 • 처음부터 죄를 저지르지 않는다 • Refactoring 을 실시한다

  26. Cf) Refactoring • 정의 • The process of changing a program's source code • without modifying its external functional behavior • in order to improve some of thenonfunctional attributes of the software. • 간단히 말하면 • 함수 / 파라메터 이름만 살짝 바꾸는 것 • 함수의 내부 구조만 바꾸는 것

  27. 어떤 때 Refactoring 을 하는가 • 확실한 성능의 개선이 있을 때 • 예) 정렬을 담당하는 함수가 하나 있는데 • 알고리즘을 Bubble Sort 로 했는데 • 나중에 정렬하는 핵심 코드만 Quick Sort 로 바꾸기 • 좀 더 가독성이 좋은 소스 코드로 바꿀 때 • 예) 변수 이름이 a, b, c, d, 이런 식인데 • 변수 이름을 gender, name, age, grade 하는 식으로 • 좀더 그 기능과 연관되는 이름으로 바꾸기

  28. TDD With Refactoring • 초록 막대 주기에서 Refactoring 을 하는 이유 • Refactoring 이후에도 초록 막대를 본다는 것은 • 진짜로 External Behavior 는 바뀌지 않았음이보장된다는 것을 의미 • Refactoring 하고 나서 빨간 막대가 나타난다는 것은 • 뭔가 Refactoring 하다가 실수 했다는 뜻이니실수를 바로잡을 기회가 생김 • TDD 방법론의 특성이 안전한 Refactoring 을 보장하는 셈이다

  29. Typical TDD Refactoring • 죄악 수습용으로서의 Refactoring • 죄악들의 공통된 특징 • Test Code 에 쓰인 상수를 • 프로그램 Code 에도 그대로 쓴다 • 어떤 형태로든 중복이 발생한다 • 코드의 중복은 나쁜 것 • 코드의 중복을 제거한다! • 성능 개선을 위한 Refactoring • 성능 개선을 알아볼 수 있는 Test 도 추가하면 좋다

  30. 중복되는 코드 찾기, #1 • 테스트 코드의 상수와 코드 내부의 상수 • 밑줄 친 부분을 잘 관찰하자 … Dollar five = new Dollar(5); five.times(2); … … int amount = 10; …

  31. 5 * 2 = 10 • 테스트 코드의 assertEqual 의 10은 사실 • New Dollar 의 5 와 five.times 의 2 의 곱이다! … Dollar five = new Dollar(5); five.times(2); … … int amount = 10; …

  32. 중복이 더 잘 드러나도록 • amount 에 대응된 10 을 5 * 2 로 고쳤다 • 이제 하나씩 하나씩 각개 격파해보자 … Dollar five = new Dollar(5); five.times(2); … … int amount = 5* 2; …

  33. 중복되는 5가 등장하는 변수를 • 상수와 같은 값을 지니는 변수를 찾자 • 객체 생성자의 파라메터에 주목! … Dollar five = new Dollar(5); … … int amount = 5 * 2; public Dollar(int amount) { …

  34. 변수를 이용하여 상수를 대체해 • 생성자의 amount 파라메터로 넘어오니까 • 굳이 Member variable 초기화에서 안해도 된다! … Dollar five = new Dollar(5); … … int amount; // = 5 * 2; public Dollar(int amount) { this.amount = amount * 2; } …

  35. Test 실행 • Test 실행 • 매끄럽게 성공한다. • 죄악의 수습 • 동일한 상수가 이곳 저곳에 있던 것을 • 최소한 상수는 중복되지 않도록 수정해 나가면 • 결국은 아름다운 코드가 나올 수 있게 된다! • 그래도 기왕이면 죄악을 저지르지 말자.

  36. 상수 2 를 없애보자 • 상수와 같은 값을 갖는 변수 찾기가 관건! … five.times(2); … … public Dollar(int amount) { this.amount = amount* 2; } void times(int multiplier) { } …

  37. 파라메터 multiplier 발견 • 용서없다. 죄악은 척살이다. … five.times(2); … … public Dollar(int amount) { this.amount = amount;// * 2; } void times(int multiplier) { this.amount *= multiplier; } …

  38. Test 실행 • 결과 • 결국 성공한다. • 더 리펙토링할 곳이 보이지 않는다 • 죄악은 전부 수습되었다 • 이 정도면 충분히 깔끔한 코드인 듯 싶다 • 테스트도 전부 통과한다 • 이번 TDD Rhythm 주기는 여기까지로 하자!

  39. 한 주기가 끝난 아름다운 소스 Public class Dollar { int amount; public Dollar(int amount) { this.amount = amount; } void times(int multiplier) { this.amount *= multiplier; } }

  40. TDD 는 매우 Agile 하다 • Comprehensive Documentation 보다Working Software • Test 를 통과하는 Software == Working Software • 무슨 수를 써서라도 Test 부터 통과시키자 • 죄악을 저질러도 상관 없다 • 용서받기만 하면 장땡이다 • 함수의 구조에 대한 복잡한 설계 과정 없이Test Code 에 맞추는 것만으로도 Working Software 를 얻을 수 있다

  41. TDD 는 매우 Agile 하다 • Follow Plan 보다 Respond to Change • 각각의 할 일들은 한번에 하나씩만 처리한다 • 어느 것을 먼저 처리해도 문제될 것은 없다 • Test 만 작성할 수 있으면 된다 • 고객 요구 조건의 변화는 결국 새로운 Test 의 추가에 지나지 않는다 • 그리고 그건 TDD Rhythm 한번 타면 해결된다 • Cf) TDD 에서는 기존의 Test Code 를 제거하는 것도 물론 일어날 수 있는 일로 보고 있다. • 엄청나게 기민하다!

  42. eXtreme Programming 과의 조화 • 경제성 • “설계” 와 “테스트” 가 하나로 합쳐짐 • 테스트 그 자체가 함수의 Interface 를 정의함! • 점진적 설계 • Test Code 는 한번에 하나씩 만드니 점진적 설계! • 자동화된 테스트 • TDD 는 언제나 자동화된 테스트를 만든다!

  43. But TDD is too eXtreme! • 모든 프로그래밍을 TDD 로 할 필요가 있나? • 반드시 Test 를 먼저 짜야만 프로젝트가 진행될 수 있는 것만은 아니다. • TDD 주기는 지나치게 엄격하다 • 테스트 실패를 굳이 매번 확인할 필요는 없다 • 언제나 “죄악” 부터 저지르고 리펙토링해? • 하나의 Test Code 만 통과시킨다고 해서 제대로 작동하는 프로그램을 못 만들 때도 있다

  44. Just one more TDD Rhythm.

  45. Recalling TO-DO List • 아까 한 개의 할일이 처리되었지만 • 두 개의 할 일이 늘어났다 • TO-DO List • $5 + 10YEN = $6 (환율이 1:10 일 때) • $5 = $5 (서로 다른 계좌)  어쨌든 이걸 골랐다 • amount 를 private로 • 이건 기존 Test Code 수정으로 충분할듯 • 반올림?

  46. Test Code 추가 • 두 개의 Dollar 객체를 만들어서 • 그 둘에게 equals 메소드를 적용하면 • true 값이 나오는지를 확인하자. public void testEquality() { assertTrue( new Dollar(5).equals( new Dollar(5)); }

  47. Test 실행 • Test 실행 • 당연히 실패한다. • 왜 굳이 실패해야 할까? • 어차피 새로운 Test 를 추가하면 실패하는 건 너무 당연한 일이 아닐까? • No! 이미 “잘못” 구현되어 있어야 하는 메소드가 있는데 그 메소드가 “잘못” 구현되어있다는 예측을 벗어난다는 것을 검증하게 되는 경우도 있음 • 그리고 Test 실패를 관찰하는 건 0.1초면 충분! • 그닥 시간낭비도 아니니까 걍 해주자. ㅋㅋ

  48. 마음놓고 죄악 저지르기 • 최대한 단순하게 equals 메소드를 작성하자 Public class Dollar { … public boolean equals(Object object) { return true; } }

  49. Test 실행과 그 후 … • 결과 • 당연히 … 잘 통과한다. • Refactoring 할 거리를 찾아야 한다 • 우리에게는 죄악이 만든 true 라는 상수가 있다 • 분명히 이 상수는 다른 상수와 중복이다 • 아까 10 = 5 * 2 였던 것처럼, • 이 true 도 뭔가 아주 당연한 연산에서 왔을 것 • 근데 … 도저히 못찾겠다면 ??

  50. 난관에 봉착했다. • 원인 분석 • Refactoring 스킬이 부족하다면 • 엄밀히 따지면 코드 중복이지만 • 대충 봐서는 파악하기 힘든 경우에 • 도저히 대처를 할 수가 없다 • 대응 방법 • Refactoring 스킬을 조홀라 키운다 • Test Code 를 좀 더 잘 짠다

More Related