Ce diaporama a bien été signalé.
Nous utilisons votre profil LinkedIn et vos données d’activité pour vous proposer des publicités personnalisées et pertinentes. Vous pouvez changer vos préférences de publicités à tout moment.

TDD (Android Unit Test)

Robolectric과 Mockito를 활용하여 TDD로 Android 개발한 경험 공유

Livres associés

Gratuit avec un essai de 30 jours de Scribd

Tout voir
  • Soyez le premier à commenter

TDD (Android Unit Test)

  1. 1. TDD (Android Unit Test) ACT Lab Kihoon Kim (koreakihoon@gmail.com)
  2. 2. test the program before you write it - kent beck -
  3. 3. TDD (Test Driven Development) 개발자는 바라는 향상 또는 새로운 함수를 정의하는 (초기적 결함을 점검하는) 자동화된 테스트 케이스를 작성한다. 그런 후에, 그 케이스를 통과하기 위한 최소한의 양의 코드를 생성한다. 그리고 마지막으로 그 새 코드를 표준에 맞도록 리팩토링한다. https://ko.wikipedia.org/wiki/테스트_주도_개발
  4. 4. The Three Rules of TDD - UncleBob 1. You are not allowed to write any production code unless it is to make a failing unit test pass. 실패하는 테스트를 작성하기 전에는 제품 코드를 작성하지 않는다. 2. You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures. 실패하는 테스트 코드를 한번에 하나 이상 작성하지 않는다. (컴파일 에러도 실패다) 3. You are not allowed to write any more production code than is sufficient to pass the one failing unit test. 현재 실패한 테스트 코드를 성공시키는데 충분한 정도로만 제품 코드를 작성한다.
  5. 5. 그래서 뭘 어떻게 하라는 건가요?
  6. 6. Design Coding Test Design Test Coding 이렇게 하던 걸 이렇게 하라는 말이죠 Refactoring Refactoring
  7. 7. 테스트 코드를 먼저 작성 한다는 것은 무엇을 테스트 할지 결정해야 한다는 것 프로그래밍 목적을 명확히 해야 한다는 것
  8. 8. TDD의 장점? ● Clean Design ● Fast Feedback ● Concrete Evidence That Your Software Works ● Write Better Code ● Reduce Gold-Plating ● Regression Test Suite ● Validates your design ● Gives confidence ● Maintains quality of implementation ● Is Automated ● No Dead code ● Easy maintenance ● Early issue discovery https://www.slideshare.net/progmania1/tdd-class-1 https://www.slideshare.net/harshit040591/test-driven-development-with-jasmine
  9. 9. 저희 팀은 이렇게 해요
  10. 10. Code User Story UI Design [PM] 도메인, 비즈니스 분석 [CX] 사용자 인터뷰 사용자 인터랙션 분석 [Dev] 구현, 테스트
  11. 11. 로그인 User story : PM As 사용자로서 I want 앱을 사용하기 위해서 So that ID/PW로 로그인 하기 원한다. # Acceptance Criteria Given ID=kihoon, PW=kim1234 를 입력된 상태에서 When 로그인 버튼을 눌렀을때 로그인 성공 시 Then 로그인 성공 페이지를 보여준다 Given ID=kihoon, PW=kim1234 를 입력된 상태에서 When 로그인 버튼을 눌렀을때 로그인 실패 시 Then “login fail” 메시지를 보여준다 개발 전 PM과 확인 할 사항 이번 스토리에서는 로그인 성공 페이지는 빈 페이지만 보여주면 되는가? => Yes 로그인 인증 API는 개발되어 있는가? => No 로그인 실패 메시지는 어떤 형식으로 보여 주나? Popup? Toast? => Toast
  12. 12. UI Design : Designer
  13. 13. 코딩을 해볼까요 : Dev
  14. 14. Test Code 를 위한 라이브러리 설정: build.gradle dependencies { … testCompile 'junit:junit:4.12' testCompile('com.squareup.assertj:assertj-android:1.1.1') { exclude group: 'com.android.support', module: 'support-annotations' } testCompile 'org.mockito:mockito-core:1.10.19' testCompile "org.robolectric:robolectric:3.2.2” ... }
  15. 15. LoginActivity 를 만들어야 겠죠 LoginActivity 도 만들고 AndroidManifest 에도 선언해 줍니다. IDE의 도움을 받으면 편합니다.
  16. 16. 복잡하지 않다면 전체 layout 부터 만들어요 만약 화면이 복잡하다면 현재 개발 할 User Story 에 나와있는 부분만 먼저 만들어요
  17. 17. 실패하는 테스트 케이스 작성 # given ID/PW가 입력된 상황 # when 로그인 버튼 클릭되면 # then 다른 화면으로 이동 하는 것을 테스트 (실제 구현 로직은 아직 없음) Test Runner Test Case Robolectric assertj
  18. 18. Run Test Code LoginButton Click 이벤트를 핸들링하는 로직이 없기 때문에 Test Fail..
  19. 19. 동작하는 구현코드 작성 이동 할 다음 화면 생성 로그인 버튼 클릭 핸들러 생성 및 처리 로직 구현 빈 Activity 생성 로그인 버튼 클릭 이벤트 핸들러
  20. 20. 테스트 성공 앞에서 만든 실제 Activity class로 변경
  21. 21. 로그인 성공/실패 처리는? 테스트 코드 변경 없음 로그인 처리를 위한 Interface 생성 보통 Dagger와 같은 DI 라이브러리를 사용하여 인젝션 처리하지만 단순히 객체 생성
  22. 22. 로그인 성공 케이스에 대한 Unit Test Mockito mocking stubbing
  23. 23. 로그인 실패 케이스에 대한 Unit Test login fail Toast 안 뜸
  24. 24. 로그인 실패시 실패 메시지 띄워주는 로직 추가 로그인 실패시 “Login Fail” 메시지를 Toast로 띄워주는 로직 추가
  25. 25. 로그인 User Story에 대한 테스트 코드 Passed
  26. 26. LoginService 로그인 Rest API가 없는 상황에서 현재 LoginService 로직 상으로 항상 true를 리턴하기 때문에 런타임에는 성공에 대한 케이스만 테스트 가능 하지만, Test Code 에서 LoginService에 대해서 stubbing 을 함으로써 성공 실패 케이스에 대해 모두 테스트 할 수 있었음
  27. 27. 무엇을 Test 해야 하나? Interface 에 대해서 테스트 코드 작성 - User Interface - Input : input text, click button… - output : show toast/dialog, launch Activity.. - API (Application Programming Interface) - return_value method_name (input_value) - void method_name() ← ex) Input: message queue, Output: Rest Call 특정 상태를 테스트 하기보다는 행위에 대해서 테스트 Gray Box Test
  28. 28. mocking 하는 대상은 무엇인가? LoginActivity LoginService dependency 테스트 대상 객체 Mocking when(subject.loginService.login(anyString(), anyString())).thenReturn(true); verify(subject.loginService).login("kihoon", "kim 1234"); subject.loginService = mock(LoginService.class);
  29. 29. 잘 정리된 robolectric tutorial 이 없네요.. https://github.com/robolectric/robolectric-samples http://robolectric.org/writing-a-test/ http://robolectric.org/javadoc/latest/ IDE의 도움을 받고, 구글 검색을 잘 해야 될 것 같아요 shadow class 에 대한 이해와 사용법을 아셔야 될 것 같아요 http://robolectric.org/extending/
  30. 30. Mockito 사용법을 익히는 것도 중요합니다 # mock 객체 생성, interface 도 가능 Comparable c= mock(Comparable.class); # 기대하는 결과를 stubbing when(c.compareTo("Mockito")).thenReturn(1); doThrow(new IOException()).when(mocksoc).close(); # mock객체의 메소드가 실행됐는지 검증 verify(test).testing(eq(12)); # 실제 객체를 테스트 하고 싶을 때 spy 객체 생성 List spy = spy(list); doReturn("foo").when(spy).get(0); # 특정 메소드가 실행될때 인자값이 잘 넘어가는지 확인 @Captor ArgumentCaptor<List<String>> captor; verify(mockedList).addAll(captor.capture()); http://site.mockito.org/ http://www.vogella.com/tutorials/Mockito/article.html
  31. 31. Test Driven Development == Test First Development ??
  32. 32. 중요한 것은.. 좋은 설계를 하고 좋은 제품을 만드는 것
  33. 33. Test를 먼저 작성하지 않으면 귀찮고 시간이 없다는 핑계로 Test Code를 안 만들게 되요 습관이 될 때 까지는 Test First 하는게 좋아요 BUT
  34. 34. 개인적으로 Test First 보다 더 중요하게 생각하는 것들..
  35. 35. Test Code를 확보하는 것 Refactoring Side effect 회귀 테스트 (Regression Test) 빠른 피드백
  36. 36. CI + Test Automation 반복 수행 가능 빠른 피드백 기능 점검은 사람보다 컴퓨터가 빠르다 Testing = Checking + Exploring https://www.thoughtworks.com/insights/blog/qa-dead 기계 사람
  37. 37. Manual Test + Bug Hunting 자동화 테스트 코드도 결국은 사람이 작성하는 것. TDD를 통해 Test Code 를 작성한다고 모든 비즈니스 요구사항을 100% 커버한다고 확신 할 수 없음 Test Code 는 AC를 위주로 작성하고 자주나오는 버그나 예외 사항에 대해서 Test Code 추가해 나감
  38. 38. Test Strategy UI Test (End to End) 와 Unit Test 간 상호 보완적으로 작성 필요 E2E test 실행은 오래 걸리지만 Unit Test로 어려운 걸 쉽게 해결하는 경우가 있음 Rest API 자동화 테스트 중요 - 생각보다 모르는 사이에 자주 바뀜 (http://rest-assured.io/) https://martinfowler.com/bliki/TestPyramid.html
  39. 39. Divide and Conquer User Story가 작게 쓰여지는 것이 중요 그렇지 않다면, 일을 작게 나눠서 개발해 나가는 연습이 필요 짧고 반복적인 개발 리듬을 찾는게 중요 그렇지 않으면 너무 깊게 설계/개발하거나, 실제 필요하지 않은 기능을 개발자 상상 만으로 개발하게됨
  40. 40. Good Enough + Time Boxing 구현은 간단한데 테스트 코드가 어려운 경우가 있음 (Thread, 외부 Library, Touch Event..) 100% 테스트 코드를 만드는 것에 집착하지 말자 한번에 완벽한 코드를 작성하려고 하지 말자 머리 속에서 설계가 되는 순간 코드로 옮겨 동작하는지 테스트 해보자 소스 코드는 시간 축을 가지고 있다. 점진 적으로 개선해 나가는 것이 좋다. 페어 프로그래밍을 한다면 ‘이정도면 충분해' 를 외쳐 주자
  41. 41. 거대한 객체를 만들지 말자 요구사항이 추가된다면?? if( A 경우 ) else if ( B 경우) else if ( C 경우) else if ( D 경우) else if ( E 경우) …… 여러 요인으로 수정되는 메소드/클래스는 요구사항 변경을 어렵게 합니다 Super Giant Huge Class Service or Activity ??
  42. 42. 객체의 역할, 책임, 협력 적절한 책임과 역할을 객체에게 부여하고 객체들 간의 협력 관계를 만들어 나가는 것이 중요 TDD를 할때 중요한 것 중 하나가 이런 객체들을 식별해내는 것 객체는 다른 객체에게 메시지를 전달 함으로써 다른 객체들과 협력을 하게 된다 (Java 에서 메시지를 전달하는 방법은 객체의 method를 호출하는 것) message message
  43. 43. 자율적인 객체 객체는 메시지를 수신했을 때만 자신의 책임을 수행하게 된다. 다른 객체는 메시지를 전달하며 협력 할 뿐, 그 객체가 내부적으로 어떻게 동작하는지 관심없다. 즉, 객체 내부의 구현이 변경되더라도 메시지가 변하지 않는다면 다른 객체를 변경하지 않아도 된다. 비즈니스 요구사항의 세부 구현을 객체 내부로 숨김으로써 변경에 대응할 수 있게 된다.
  44. 44. 인터페이스(interface)를 사용하자 OOP 에서 자신의 책임을 다른 객체에게 public 하게 제공하는 것이 바로 interface 이다. interface 를 통해 객체 간 의존성을 낮출 수 있다. interface 를 통해 객체가 자율적으로 동작할 수 있게 해준다. java interface에는 field 를 선언 할 수 없다. 즉, 상태가 아닌 행위를 테스트 해야 한다. message
  45. 45. 사용하는 언어를 통일하자 개념적 설계, 구조적 설계 모델을 구현 코드에 최대한 반영 DESIGNER USER SYSTEM
  46. 46. 불필요 할지도 모르는 기능의 완벽한 품질 보다 버그가 있더라도 사용자의 빠른 피드백을 받는게 중요.. 사용자 피드백에 의한 요구사항 변경을 환영하는 마음 가짐을 갖는 것도 중요하지만 대응 가능한 소스코드를 갖고 있는 것 역시 중요
  47. 47. Q & A 감사합니다

×