Your SlideShare is downloading. ×
0
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Tdd objective c
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Tdd objective c

859

Published on

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
859
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
8
Comments
0
Likes
0
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Разработка через тестирование iOS, Bowling Game Kata Test Driven Development Ivan Dyachenko <ivan.dyachenko@gmail.com>© Luxoft Training 2012 http://uamobile.in.ua/ Thursday, December 6, 12
  • 2. Kent Beck Экстремальное программирование (XP) Разработка через тестирование (TDD) Agile Manifesto в 2001 году.© Luxoft Training 2012 Thursday, December 6, 12
  • 3. Whole Team Collective Coding Test-Driven Ownership Standard Development Customer Pair Planning Refactoring Tests Programming Game Continuous Sustainable Simple Design Integration Pace Metaphor Small Releases© Luxoft Training 2012 Extreme Programming Practices Thursday, December 6, 12
  • 4. Whole Team Collective Coding Test-Driven Ownership Standard Development Customer Pair Planning Refactoring Tests Programming Game Continuous Sustainable Simple Design Integration Pace Metaphor Small Releases© Luxoft Training 2012 Extreme Programming Practices Thursday, December 6, 12
  • 5. TDD «Чистый код, который работает»© Luxoft Training 2012 Thursday, December 6, 12
  • 6. Мифы TDD Unit tests == TDD TDD == 100% coverage TDD == время * 2 TDD == серебряная пуля© Luxoft Training 2012 Thursday, December 6, 12
  • 7. Два простых правила TDD 1 Пишем новый код только тогда, когда автоматический код не сработал 2 Удаляем дублирование© Luxoft Training 2012 Thursday, December 6, 12
  • 8. © Luxoft Training 2012 Мантра TDD – “red, green, refactor” Thursday, December 6, 12
  • 9. RED / GREEN / REFACTOR 0 Подумай© Luxoft Training 2012 Thursday, December 6, 12
  • 10. RED / GREEN / REFACTOR 0 Подумай 1 Напиши тест© Luxoft Training 2012 Thursday, December 6, 12
  • 11. RED / GREEN / REFACTOR 0 Подумай 1 Напиши тест 2 Скомпилируй© Luxoft Training 2012 Thursday, December 6, 12
  • 12. RED / GREEN / REFACTOR 0 Подумай 1 Напиши тест 2 Скомпилируй 3 Исправь ошибки© Luxoft Training 2012 Thursday, December 6, 12
  • 13. RED / GREEN / REFACTOR 0 Подумай 1 Напиши тест 2 Скомпилируй 3 Исправь ошибки 4 Запусти и убедись что тесты упали© Luxoft Training 2012 Thursday, December 6, 12
  • 14. RED / GREEN / REFACTOR 0 Подумай 1 Напиши тест 2 Скомпилируй 3 Исправь ошибки 4 Запусти и убедись что тесты упали 5 Напиши код© Luxoft Training 2012 Thursday, December 6, 12
  • 15. RED / GREEN / REFACTOR 0 Подумай 1 Напиши тест 2 Скомпилируй 3 Исправь ошибки 4 Запусти и убедись что тесты упали 5 Напиши код 6 Запусти и убедись что тесты прошли© Luxoft Training 2012 Thursday, December 6, 12
  • 16. RED / GREEN / REFACTOR 0 Подумай 1 Напиши тест 2 Скомпилируй 3 Исправь ошибки 4 Запусти и убедись что тесты упали 5 Напиши код 6 Запусти и убедись что тесты прошли© Luxoft Training 2012 7 Рефакторинг Thursday, December 6, 12
  • 17. RED / GREEN / REFACTOR 0 Подумай 1 Напиши тест 2 Скомпилируй 3 Исправь ошибки Повтори 4 Запусти и убедись что тесты упали 5 Напиши код 6 Запусти и убедись что тесты прошли© Luxoft Training 2012 7 Рефакторинг Thursday, December 6, 12
  • 18. Ошибки TDD Писать тест после кода Писать тест который сразу проходит Писать сразу много тестов© Luxoft Training 2012 Thursday, December 6, 12
  • 19. Инструменты § OCUnit/SenTestingKit начиная IPhone SDK 2.2 § GHUnit § Google Toolkit for Mac § OCMock § OCHamcrest § Kiwi § Cedar § …© Luxoft Training 2012 Thursday, December 6, 12
  • 20. OCUnit § Object-oriented tests § Very low overhead § Tests are in the same language as the implementation § Test case classes cohabit with classes they test § Promotes aggressive refactoring § Helps capture requirements, expose dependencies § Total integration in the development process § Records testing expertise© Luxoft Training 2012 § Tests frameworks, bundles, or applications § Easy installation Thursday, December 6, 12
  • 21. OCUnit Asserts TestCase § STAssertNil § test<Test Case> § STAssertNotNil § setUp § STAssertTrue § tearDown § STAssertFalse § STAssertEquals § STAssertEqualObjects § STFail© Luxoft Training 2012 § ... Thursday, December 6, 12
  • 22. Пример Bowling Game Kata - подсчет очков игры в боулинг www.objectmentor.com wiki.agiledev.ru© Luxoft Training 2012 www.slideshare.net Thursday, December 6, 12
  • 23. © Luxoft Training 2012 Thursday, December 6, 12
  • 24. Правила игры в боулинг Раунды Подсчет очков § 10 раундов (frame-ов) § 10 сразу (strike). Заканчивается досрочно. § В одном  frame – 2 броска 10 очков + pins + pins § Цель – выбить кегли (pins) § 10 очков со второго броска (spare) § Выигрывает набравший больше 10 очков + pins всех очков § Max 300 очков (12 strikes) Последний frame § 1-й strike – дает возможность бросить еще два раза© Luxoft Training 2012 § 2-й spare – дает возможность бросить еще одни раз Thursday, December 6, 12
  • 25. Надо написать BowlingGame + roll(pins : int) + score() : int Написать класс BowlingGame, который имеет два метода • roll (pins : int) – вызывается каждый раз когда игрок бросает шар. Pins – количество выбитых кеглей в этом броске • score() : int – вызывается в конце игры. Показывает результат игры© Luxoft Training 2012 Thursday, December 6, 12
  • 26. A quick design session Нам нужен BowlingGame класс BowlingGame + roll(pins : int)© Luxoft Training 2012 Thursday, December 6, 12
  • 27. A quick design session BowlingGame Frame + roll(pins : int) + score() : int Игра имеет 10 фреймов© Luxoft Training 2012 Thursday, December 6, 12
  • 28. A quick design session BowlingGame Frame Roll + roll(pins : int) + score() : int - pins : int Каждый фрейм состоит из одного или двух бросков© Luxoft Training 2012 Thursday, December 6, 12
  • 29. A quick design session BowlingGame Frame Roll + roll(pins : int) + score() : int - pins : int Tenth Frame Последний фрейм© Luxoft Training 2012 содержит два или три броска Thursday, December 6, 12
  • 30. A quick design session BowlingGame Frame Roll + roll(pins : int) + score() : int - pins : int Score функция должна пройтись по всем фреймам и посчитать результат Tenth Frame© Luxoft Training 2012 Thursday, December 6, 12
  • 31. A quick design session Strike или Spare зависит от количества Next Frame выбитых кеглей в Frame BowlingGame Frame Roll + roll(pins : int) + score() : int - pins : int Tenth Frame© Luxoft Training 2012 Thursday, December 6, 12
  • 32. Готовим среду для тестирования +© Luxoft Training 2012 Thursday, December 6, 12
  • 33. Еще раз повторим правила Раунды Подсчет очков § 10 раундов (frame-ов) § 10 сразу (strike). Заканчивается досрочно. § В одном  frame – 2 броска 10 очков + pins + pins § Цель – выбить кегли (pins) § 10 очков со второго броска (spare) § Выигрывает набравший больше 10 очков + pins всех очков § Max 300 очков (12 strikes) Последний frame § 1-й strike – дает возможность бросить еще два раза© Luxoft Training 2012 § 2-й spare – дает возможность бросить еще одни раз Thursday, December 6, 12
  • 34. Пишем код© Luxoft Training 2012 Thursday, December 6, 12
  • 35. Test List /* should score zero on gutter game Подумай should score twenty when all one should score spare correctly should score all spares correctly should score strike correctly should score super game */ #import "BowlingGameTests.h” @implementation BowlingGameTests - (void)setUp { [super setUp]; } - (void)tearDown { [super tearDown];© Luxoft Training 2012 } @end Thursday, December 6, 12
  • 36. Assert First - (void)testGutterGame { STAssertEquals(0, [game score], nil); }© Luxoft Training 2012 Thursday, December 6, 12
  • 37. Test First - (void)testGutterGame { BowlingGame *game = [[BowlingGame alloc] init]; for (int i = 0; i < 20; i++) { [game roll:0]; } STAssertEquals(0, [game score], nil); } Пишем тест игнорируя ошибки компилятора© Luxoft Training 2012 Thursday, December 6, 12
  • 38. Исправляем ошибки, пишем код - (void)testGutterGame { BowlingGame *game = [[BowlingGame alloc] init]; for (int i = 0; i < 20; i++) { [game roll:0]; } STAssertEquals(0, [game score], nil); } @implementation BowlingGame - (void)roll:(int)pins { } - (int)score { Пишем минимум return 0; кода! KISS }© Luxoft Training 2012 @end Thursday, December 6, 12
  • 39. Следующий тест - (void)testAllOne Тест падает { BowlingGame *game = [[BowlingGame alloc] init]; for (int i = 0; i < 20; i++) { [game roll:1]; } STAssertEquals(20, [game score], nil); }© Luxoft Training 2012 Thursday, December 6, 12
  • 40. Пишем код - (void)testAllOne { BowlingGame *game = [[BowlingGame alloc] init]; for (int i = 0; i < 20; i++) { [game roll:1]; Тест проходит } STAssertEquals(20, [game score], nil); } #import "BowlingGame.h" @implementation BowlingGame - (void)roll:(int)pins { score += pins; } - (int)score { return score; }© Luxoft Training 2012 @end Thursday, December 6, 12
  • 41. Убираем дублирование - (void)testGutterGame { int n = 20; int pins = 0; for (int i = 0; i < n; i++) { [game roll:pins]; } STAssertEquals(0, [game score], nil); }© Luxoft Training 2012 Thursday, December 6, 12
  • 42. Рефакторим - (void)testGutterGame { [self rollMany:0 times:20]; STAssertEquals(0, [game score], nil); } - (void)testAllOne { [self rollMany:1 times:20]; STAssertEquals(20, [game score], nil); } - (void)rollMany:(int)pins times:(int)n { for (int i = 0; i < n; i++) { [game roll:pins]; } }© Luxoft Training 2012 Thursday, December 6, 12
  • 43. Проверка на Spare 6 3 Тест падает 4 - 10 + 3 3 - (void)testScoreSpare { [game roll:5]; // spare [game roll:5]; [game roll:3]; [self rollMany:17 times:0]; STAssertEquals(16, [game score], nil); }© Luxoft Training 2012 Thursday, December 6, 12
  • 44. Design review #import "BowlingGame.h" roll – занимается подсчетом очков, но @implementation BowlingGame имя метода не указывает на это - (void)roll:(int)pins { score += pins; } - (int)score { return score; } score – не занимается подсчетом @end очков, хотя имя указывает, что должна© Luxoft Training 2012 Thursday, December 6, 12
  • 45. Redesign Добавляем метод в Ignore //- (void)testScoreSpare { // [game roll:5]; // spare // [game roll:5]; // [game roll:3]; // [self rollMany:17 times:0]; // STAssertEquals(16, [game score], nil); //}© Luxoft Training 2012 Thursday, December 6, 12
  • 46. Redesign #import "BowlingGame.h" @implementation BowlingGame - (void)roll:(int)pins { rolls[currentRoll++] = pins; } - (int)score { int score = 0; for (int i = 0; i < 20; i++) score += rolls[i]; return score; } @end© Luxoft Training 2012 Thursday, December 6, 12
  • 47. Убираем Ignore - (void)testScoreSpare { [game roll:5]; // spare [game roll:5]; [game roll:3]; Тест падает [self rollMany:17 times:0]; STAssertEquals(16, [game score], nil); }© Luxoft Training 2012 Thursday, December 6, 12
  • 48. Пишем код - (int)score { int score = 0; for (int i = 0; i < 20; i++) if (rolls[i] + rolls[i + 1] == 10) //spare score += 10 + rolls[i + 2]; ... score += rolls[i]; return score; } Хорошая идея! За одним исключением – это не работает У нас все еще проблемы с дизайном. Очевидно, надо считать очки по фреймам© Luxoft Training 2012 Thursday, December 6, 12
  • 49. Очередная сессия Redesign //- (void)testScoreSpare { // [game roll:5]; // spare // [game roll:5]; // [game roll:3]; // [self rollMany:17 times:0]; // Добавляем метод STAssertEquals(16, [game score], nil); //} в Ignore© Luxoft Training 2012 Thursday, December 6, 12
  • 50. Refactoring - (int)score { int score = 0; int i = 0; for (int frame = 0; frame < 10; frame++) { score += rolls[i] + rolls[i + 1]; i += 2; } return score; }© Luxoft Training 2012 Thursday, December 6, 12
  • 51. Убираем Ignore - (void)testScoreSpare { [game roll:5]; // spare [game roll:5]; Тест падает [game roll:3]; [self rollMany:17 times:0]; STAssertEquals(16, [game score], nil); }© Luxoft Training 2012 Thursday, December 6, 12
  • 52. Пишем код - (int)score { int score = 0; int i = 0; for (int frame = 0; frame < 10; frame++) { if (rolls[i] + rolls[i + 1] == 10) {// spare score += 10 + rolls[i + 2]; i += 2; } else { score += rolls[i] + rolls[i + 1]; i += 2; } } return score; }© Luxoft Training 2012 Thursday, December 6, 12
  • 53. Design review Плохое имя переменной - (int)score { int score = 0; int i = 0; for (int frame = 0; frame < 10; frame++) { if (rolls[i] + rolls[I + 1] == 10) {// spare score += 10 + rolls[i + 2]; i += 2; } Плохо иметь комментарий в else { условии score += rolls[i] + rolls[i + 1]; i += 2; } } return score; }© Luxoft Training 2012 Thursday, December 6, 12
  • 54. Refactoring - (int)score { int score = 0; int ballIndex = 0; for (int frame = 0; frame < 10; frame++) { if ([self isSpare:ballIndex]) { score += 10 + rolls[ballIndex + 2]; ballIndex += 2; } else { score += rolls[ballIndex] + rolls[ballIndex + 1]; ballIndex += 2; } } return score; } - (BOOL)isSpare:(int)ballIndex {© Luxoft Training 2012 return rolls[ballIndex] + rolls[ballIndex+1] == 10; } Thursday, December 6, 12
  • 55. Проверка на Strike 10 3 * 4 10 + 3 + 4 3+4 Комментарий в тесте - (void)testScoreStrike { [game roll:10]; // strike [game roll:3]; [game roll:4]; [self rollMany:16 times:0]; STAssertEquals(24, [game score], nil); }© Luxoft Training 2012 Thursday, December 6, 12
  • 56. Пишем код - (int)score { int score = 0; int ballIndex = 0; for (int frame = 0; frame < 10; frame++) { if (rolls[ballIndex] == 10) { score += 10 + ! ! ! ! ! ! rolls[ballIndex + 1] + ! ! ! ! ! ! ! ! ! rolls[ballIndex + 2]; ballIndex++; } else if ([self isSpare:ballIndex]) { score += 10 + rolls[ballIndex + 2]; ballIndex += 2; } else { score += rolls[ballIndex] + rolls[ballIndex + 1]; ballIndex += 2; } }© Luxoft Training 2012 return score; } Thursday, December 6, 12
  • 57. Design review - (int)score { int score = 0; Комментарий для условия int ballIndex = 0; for (int frame = 0; frame < 10; frame++) { if (rolls[ballIndex] == 10) { // strike score += 10 + rolls[ballIndex + 1] + rolls[ballIndex + 2]; ballIndex++; } else if ([self isSpare:ballIndex]) { score += 10 + rolls[ballIndex + 2]; ballIndex += 2; } else { score += rolls[ballIndex] + rolls[ballIndex + 1]; ballIndex += 2; } } return score;© Luxoft Training 2012 } Непонятное выражение Thursday, December 6, 12
  • 58. Refactoring - (int)score { int score = 0; int ballIndex = 0; for (int frame = 0; frame < 10; frame++) { if ([self isStrike:ballIndex]) { score += 10 + [self strikeBonus:ballIndex]; ballIndex++; } else if ([self isSpare:ballIndex]) { score += 10 + [self spareBonus:ballIndex]; ballIndex += 2; } else { score += [self sumOfBallsInFrame:ballIndex]; ballIndex += 2; } } return score; }© Luxoft Training 2012 Thursday, December 6, 12
  • 59. Refactoring - (void)testScoreStrike { [self rollStrike]; [game roll:3]; [game roll:4]; [self rollMany:16 times:0]; STAssertEquals(24, [game score], nil); } - (void)rollStrike { [game roll:10]; }© Luxoft Training 2012 git checkout bowling-0.8 Thursday, December 6, 12
  • 60. Контрольный пример - (void)testPrefectGame { [self rollMany:10 times:12]; STAssertEquals(300, [game score], nil); }© Luxoft Training 2012 Thursday, December 6, 12
  • 61. Cтратегии запуска тестов § IDE § Console § CocoaPods § Maven § Test Runner § CI § File watcher© Luxoft Training 2012 Thursday, December 6, 12
  • 62. Continuous integration Hudson Team City© Luxoft Training 2012 Thursday, December 6, 12
  • 63. Преимущества от TDD Меньше ошибок Проще рефакторить Документация Лучший дизайн кода Быстрее процесс разработки© Luxoft Training 2012 Thursday, December 6, 12
  • 64. BDD Behavior Driven Development (BDD)© Luxoft Training 2012 Thursday, December 6, 12
  • 65. BDD – что это? Language© Luxoft Training 2012 Thursday, December 6, 12
  • 66. Difference between TDD, BDD & ATDD TDD ATDD© Luxoft Training 2012 Thursday, December 6, 12
  • 67. BDD DDD-Domain Driven Testing + DSL + GIVEN / WHEN / THEN Спецификация Тесты Документация© Luxoft Training 2012 Thursday, December 6, 12
  • 68. Kiwi describe(@"BowlingGame", ^{ it(@"should score zero on gutter game", ^{ rollMany(20, 0); [[theValue([game score]) should] equal:theValue(0)]; }); it(@"should score twenty when all one", ^{ rollMany(20, 1); [[theValue([game score]) should] equal:theValue(20)]; }); it(@"should score spare correctly", ^{ [game roll:5]; [game roll:5]; [game roll:3]; rollMany(17, 0); [[theValue([game score]) should] equal:theValue(16)]; }); it(@"should score strike correctly", ^{ [game roll:10]; [game roll:3];© Luxoft Training 2012 [game roll:4]; rollMany(16, 0); [[theValue([game score]) should] equal:theValue(24)]; }); Thursday, December 6, 12
  • 69. © Luxoft Training 2012 Thursday, December 6, 12
  • 70. © Luxoft Training 2012 Thursday, December 6, 12
  • 71. *.feature # language: ru Функционал: Авторизация пользователей Чтобы указывать себя автором снипетов, голосовать за снипеты и нарабатывать карму, пользователи должны иметь возможность регистрироваться Сценарий: Успешная авторизация с указываемыми логином и паролем Допустим я зарегистрированный пользователь "User12" с паролем "User1212" И я на странице Авторизация Если ввожу в поле Логин "User12" И ввожу в поле Пароль "User1212" И кликаю кнопку "Войти" То я должен увидеть уведомление "Добро пожаловать!" И я должен оказаться на странице Страница пользователя© Luxoft Training 2012 Thursday, December 6, 12
  • 72. *.feature© Luxoft Training 2012 Thursday, December 6, 12
  • 73. Вопросы ?© Luxoft Training 2012 Thursday, December 6, 12
  • 74. Разработка через тестирование IDyachenko@luxoft.com git clone git://github.com/ivan-dyachenko/Trainings.git© Luxoft Training 2012 https://github.com/ivan-dyachenko/Trainings Thursday, December 6, 12

×