Upgrade to Pro — share decks privately, control downloads, hide ads and more …

"Test-Driven" в Rails

5ca07e641fada5a88a09277c45bd7c1b?s=47 Stefan Kanev
February 03, 2012

"Test-Driven" в Rails

Презентацията от Empower on Rails за тестове и TDD в Rails.

5ca07e641fada5a88a09277c45bd7c1b?s=128

Stefan Kanev

February 03, 2012
Tweet

Transcript

  1. “Test-Driven” в Rails Стефан Кънев http://skanev.com/ @skanev Empower on Rails

    1 февруари 2012 София
  2. Здравейте, аз съм Стефан

  3. 5 години

  4. Всеки път

  5. “Разчупен лед”

  6. None
  7. 3. 14159265358979323846264338327950288419716939937510 58209749445923078164062862089986280348253421170679 82148086513282306647093844609550582231725359408128 48111745028410270193852110555964462294895493038196 44288109756659334461284756482337867831652712019091 45648566923460348610454326648213393607260249141273 72458700660631558817488152092096282925409171536436 78925903600113305305488204665213841469519415116094 33057270365759591953092186117381932611793105118548

    07446237996274956735188575272489122793818301194912 98336733624406566430860213949463952247371907021798 60943702770539217176293176752384674818467669405132 00056812714526356082778577134275778960917363717872 14684409012249534301465495853710507922796892589235 42019956112129021960864034418159813629774771309960 51870721134999999837297804995105973173281609631859 50244594553469083026425223082533446850352619311881 71010003137838752886587533208381420617177669147303 59825349042875546873115956286388235378759375195778 18577805321712268066130019278766111959092164201989 38095257201065485863278865936153381827968230301952 03530185296899577362259941389124972177528347913151 55748572424541506959508295331168617278558890750983 81754637464939319255060400927701671139009848824012 85836160356370766010471018194295559619894676783744 94482553797747268471040475346462080466842590694912 93313677028989152104752162056966024058038150193511 25338243003558764024749647326391419927260426992279 67823547816360093417216412199245863150302861829745 55706749838505494588586926995690927210797509302955
  8. instance Show Board where show (Board ps) = let ordered

    = (sort . swap) ps ranks = map (showRank ordered) [8,7..1] board = intersperse "--+--+--+--+--+--+--+--" ranks rlabels = intersperse " " (map (\n->(show n)++" ") [8,7..1]) flabels = " a b c d e f g h" in unlines $ zipWith (++) rlabels board ++ [flabels] where swap = map (\(a,b)->(b,a)) showRank ps r = let rnk = filter (\(p,_)->(rank p)==r) ps cs = map (showPiece rnk) [A .. H] in concat (intersperse "|" cs) showPiece ps f = maybe " " (show . snd) (find (\(p,_)->(file p)==f) ps)
  9. None
  10. Физическа болка

  11. Хора с мустаци

  12. None
  13. None
  14. Васил с мустаци

  15. Божидар с мустаци

  16. None
  17. сега по-сериозно

  18. защо тестове?

  19. — TDD

  20. Написах първия си тест в първия си работен ден.

  21. Започнах да се занимавам с Rails основно заради възможностите му

    за тестване.
  22. None
  23. “If you don’t write tests, you need to finish learning

    how to write code.”
  24. Тестването в Rails е лесно

  25. Всички тестват - имате кой да попитате, имате къде да

    погледнете.
  26. Научаването на автоматизирано тестване е пътешествие...

  27. ...има моменти на действие...

  28. ...и моменти на размисъл.

  29. Всяко пътешествие се нуждае от карта

  30. С тази презентация ще ви начертая карта на тестването в

    Ruby и Rails.
  31. 1. Защо пишем тестове? 2. Структура и понятия 3. Често

    срещани грешки 4. Инструменти в Ruby 5. Test-Driven Development 6. Mocks 7. Behavior-Driven Development План
  32. Как изглежда всичко това в Ruby?

  33. Няма да говоря за прости неща, които може да си

    прочетете сами - ще наблегна на по-трудното за намиране
  34. червено жълто зелено синьо червено синьо жълто зелено синьо

  35. ...са виждали тестове? ...са писали тестове? ...пишат теста преди кода?

    ...са ползвали mock? Колко от вас...
  36. 1. Защо пишем тестове? 2. Структура и понятия 3. Често

    срещани грешки 4. Инструменти в Ruby 5. Test-Driven Development 6. Mocks 7. Behavior-Driven Development
  37. “Плуването подобрява здравето, имунната система, тонуса и сексуалния живот”

  38. “Бягането подобрява здравето, имунната система, тонуса и сексуалния живот”

  39. “Тестването подобрява здравето, имунната система, тонуса и сексуалния живот”

  40. Тестовете правят промяната на приложените по-лесна.

  41. None
  42. None
  43. None
  44. None
  45. Safety Net

  46. Документация

  47. Defect Localization

  48. Bug Repellent

  49. Тестовете улесняват поддръжката на проекта.

  50. Лошо написаните тестове правят системата по-трудна за поддръжка

  51. Тестовете също са код. Принципите за качествен код важат и

    за тях
  52. какви трябва да бъдат тестовете?

  53. лесни за пускане “Не трябва да губя енергия за пускане

    на тестове”
  54. гъвкави “Тестовете трябва да ми помагат да развивам системата”

  55. прости “Трябва да мога лесно и бързо да разбирам и

    променям тестове”
  56. изразителни “Тестовете трябва да разказват за системата и да ми

    помагат да я разбера”
  57. бързи “Пускането на тестове не трябва да ме разсейва от

    проблема, който решавам”
  58. 1. Защо пишем тестове? 2. Структура и понятия 3. Често

    срещани грешки 4. Инструменти в Ruby 5. Test-Driven Development 6. Mocks 7. Behavior-Driven Development
  59. xUnit

  60. Kent Beck SUnit, Smalltalk paper in 1994

  61. Повечето тестови библиотеки са основани на xUnit идеите

  62. assertion test method test case

  63. class Stack < Test::Unit::TestCase def setup @stack = Stack.new end

    def test_empty assert @stack.empty? @stack.push 42 assert !@stack.empty? end def test_pop @stack.push 42 @stack.push 5 assert_equal 5, @stack.pop assert_equal 42, @stack.pop asser_raise(StackEmptyError) { @stack.pop } end end
  64. ! testrb stack_test.rb Loaded suite stack_test.rb Started .. Finished in

    0.000629 seconds. 2 tests, 2 assertions, 0 failures, 0 errors
  65. System Under Test (SUT) друго име за “какво точно тестваме”

    ще го произнасям “СУТ” всеки тест трябва да има ясна такава помага да категоризираме тестовете
  66. SUT Tests Unit tests Integration tests

  67. Unit Integration Тества един клас Изолиран с mock-ове Бърз Помага

    за дизайна Тества компонент Понякога има stub-ове Бавен Помага за верификацията
  68. Acceptance Test Тества целия стек Изразен на domain ниво Ползва

    потребителския интерфейс Много бавен Понякога със Selenium
  69. Терминологията в Rails с Test::Unit е различна

  70. По принцип Rails + Test::Unit unit test ~ unit test

    integration test functional test acceptance test integration test
  71. Four-Phase Test

  72. Setup Exercise Verify Tear-Down

  73. Setup Exercise Verify Tear-Down Поставяме системата в състояние, в което

    може да я тестваме (fixture)
  74. Setup Exercise Verify Tear-Down Взаимодействаме със системата, за да предизвикаме

    някакво поведение
  75. Setup Exercise Verify Tear-Down Проверяваме, че интеракцията е довела до

    очакваните резултати
  76. Setup Exercise Verify Teardown Разрушаваме fixture-а, за да изолираме останалите

    тестове от този
  77. Ясното разделяне на фази прави теста много по-разбираем

  78. Test Doubles

  79. Stubs Mocks Spies Fakes

  80. Ползват се най-вече stubs и mocks. Последните са малко неразбрани.

  81. 1. Защо пишем тестове? 2. Структура и понятия 3. Често

    срещани грешки 4. Инструменти в Ruby 5. Test-Driven Development 6. Mocks 7. Behavior-Driven Development
  82. Broken Promises

  83. “Throwing the baby out with the bathwater”

  84. Unsustainable Tests

  85. Ще ви покажа често срещани проблеми и как може да

    ги решите
  86. Fragile Test

  87. Тестовете са чувствителни на четири неща: interface, behavior, data, context

  88. Interface Sensitivity Тестът зависи от публичен интерфейс на клас(ове), който

    се променя
  89. class RegistrationTest < Test::Unit::TestCase def test_registering_a_valid_user registration = Registration.new registration.email

    = 'stefan@example.org' registration.password = 'larodi' registration.submit assert_equal 1, User.count assert_equal 'stefan@example.org', User.first.email end def test_user_without_an_email registration = Registration.new registration.email = '' # ... end end
  90. registration = Registration.new registration.email = 'stefan@example.org' registration.password = 'larodi' registration.submit

  91. представете си следния refactoring

  92. registration = Registration.new registration.email = 'stefan@example.org' registration.password = 'larodi' registration.submit

    registration = Registration.new email: 'stefan@example.org', password: 'larodi' registration.register
  93. Дори кодът да работи и клиентите на Registration да бъдат

    променени, теста не минава
  94. По-лошо - има няколко теста, които не минават и трябва

    да обновим всичките
  95. None
  96. class RegistrationTest < Test::Unit::TestCase def test_registering_a_valid_user registration = Registration.new registration.email

    = 'stefan@example.org' registration.password = 'larodi' registration.submit assert_equal 1, User.count assert_equal 'stefan@example.org', User.first.email end # ... end
  97. class RegistrationTest < Test::Unit::TestCase def create_user(email, password) registration = Registration.new

    registration.email = email registration.password = password registration.submit end def test_registering_a_valid_user create_user 'stefan@example.org', 'larodi' assert_equal 1, User.count assert_equal 'stefan@example.org', User.first.email end # ... end
  98. При промяна на интерфейса, трябва да обновите само едно място

    в тестовете
  99. Behavior Sensitivity Поведението на системата се променя по някакъв начин,

    от който теста зависи
  100. Местите софтуера от Европа в щатите и този израз започва

    да връща false User.new(age: 18).can_drink?
  101. Обикновено искате тестовете да не минават, когато има промяна поведението...

  102. но

  103. ...коя фаза на теста зависи от промененото поведение? Setup Exercise

    Verify Tear-Down ОК ошоЛ
  104. Променяте user.rb и order_test.rb се чупи. Разваля defect localization

  105. Добре е изграждането на fixture-а да не зависи от бизнес

    логиката на приложението ви
  106. factory_girl

  107. Data Sensitivity Променяте формата на данните и теста ви се

    проваля
  108. class UserTest < Test::Unit::TestCase def test_name_shortening user = User.create! name:

    'Stefan Kanev' assert 'Stefan K.', user.short_name end end Въпрос: какво става, ако искаме да добавим задължително поле nickname?
  109. Отговор: 571 failing tests

  110. class UserTest < Test::Unit::TestCase def test_name_shortening user = create_user name:

    'Stefan Kanev' assert 'Stefan K.', user.short_name end end
  111. factory_girl

  112. Context Sensitivity Контекста, в който системата се изпълнява се е

    променил по някакъв начин
  113. Популярният пример е код, зависещ от Time.now. Виждал съм тестове,

    които не минават от 23:00 до 00:00. Или тестове, които не минават като занеса компютъра във Виена.
  114. Други източници са външни зависимости, като база от данни или

    Solr.
  115. Ако тестовете страдат от много context sensitivity, едно решение е

    да се намали SUT-а.
  116. Fragile Fixture Контекста, в който системата се изпълнява се е

    променил по някакъв начин
  117. Obscure Test

  118. Eager Test Един тест проверява твърде много функционалност в един

    метод
  119. class FlightTest < Test::Unit::TestCase def test_flight_mileage_as_km flight = Flight.new(valid_flight_number) assert_equals

    valid_flight_number, flight.number assert_equals '', flight.airline_code assert_nil flight.airline flight.mileage = 1122 assert_equals 1820, flight.mileage_as_km flight.cancel assert_raise { flight.mileage_as_km } end end
  120. Irrelevant Information Един тест има много разсейваща информация, която не

    е нужда за разбирането на теста
  121. class UserTest < Test::Unit::TestCase def test_eligible_to_drink user = User.new({ age:

    18, billing_address: Address.new({ country: 'United Kingdom', city: 'London', address_1: '221B Baker str.', }), shipping_address: Address.new({ country: 'United Kingdom', city: 'London', address_1: '112 Tabernacle str.' address_2: '26 City Lofts', }) }) assert_true user.eligible_to_drink? end end
  122. Indirect Testing Тестът изразява упражнението и проверката по индиректен начин

  123. Erratic Test

  124. Когато тестовете ви не минават от време на време.

  125. Когато става на Continuous Integration сървъра

  126. Тестовете трябва да са напълно детерминистични. Иначе преставате да им

    вярвате.
  127. Erratic tests, reason #1: Selenium

  128. Slow Test

  129. Имате твърде много интеграционни тестови

  130. В системата която тествате има асинхронност

  131. Просто твърде много тестове

  132. 1. Защо пишем тестове? 2. Структура и понятия 3. Често

    срещани грешки 4. Инструменти в Ruby 5. Test-Driven Development 6. Mocks 7. Behavior-Driven Development
  133. Няма да говоря за прости неща, които може да си

    прочетете сами - ще наблегна на по-трудното за намиране
  134. Има Rails guide за Test::Unit, който го обяснява по-ефективно отколкото

    презентация
  135. RSpec

  136. class UniverseTest < Unit::Test::TestCase def test_answer assert 42, Universe.answer end

    end describe Universe do it "knows the answer" do Universe.answer.should eq 42 end end
  137. Имената на тестовете стават значително по-дескриптивни, понеже са цели изречения

  138. Проверките се четат много по-естествено assert 42, Universe.answer Universe.answer.should eq

    42
  139. Използва Behavior-Driven терминология. За това: по-късно

  140. class Stack < Test::Unit::TestCase def setup @stack = Stack.new end

    def test_empty assert @stack.empty? @stack.push 42 assert !@stack.empty? end def test_pop @stack.push 42 @stack.push 5 assert_equal 5, @stack.pop assert_equal 42, @stack.pop asser_raise(StackEmptyError) { @stack.pop } end end
  141. describe Stack do let(:stack) { Stack.new } it "can tell

    whether it is empty" do stack.should be_empty stack.push 42 stack.should_not be_empty end it "should pop the items in reverse order" do stack.push 42 stack.push 5 stack.pop.should eq 5 stack.pop.should eq 42 lambda { stack.pop }.should raise_error(StackEmptyError) end end
  142. Capybara

  143. None
  144. fill_in 'Username', with: 'skanev' fill_in 'Password', with: 'larodi' check 'Remember

    me' click_button 'Register' response.should have_text('Welcome!')
  145. Използва много XPath, за да ви даде удобен интерфейс към

    документа
  146. По подразиране изполва rack-test, който симулира браузър през HTTP

  147. Може да го накарате да работи със Selenium, envjs, zombie.js

    и дори HtmlUnit (Java)
  148. Cucumber

  149. Feature: Purchasing things In order for us to make money

    the user should be allowed to easily purchase our products Scenario: Purchases for more than 2500 should offer 20% Given the following products: | Name | Price | | MacBook Pro | 2000 | | ThinkPad | 1000 | When I add 1 "MacBook Pro" to my basket And I add 1 "ThinkPad" to my basket Then the final price should be 2600
  150. Given /^the following products$/ do |table| ... end When /^I

    add (\d+) "(.*?)" to my basket$/ do |count, name| ... end Then /^the final price should be (\d+)$/ do |price| ... end
  151. Gherkin

  152. Cucumber ви позволява да изразявате acceptance тестове на домейн езика

  153. None
  154. Функционалност: Купуване на продукти За да печелим пари потребителят трябва

    да може лесно да пазарува продукти Сценарий: Поръчките за повече от 2000 трябва да имат 20% отстъпка Дадено че има следните три продукта: | Име | Price | | MacBook Air | 2000 | | ThinkPad | 1000 | Когато добавя 1 "MacBook Air" в кошницата си И добавя 2 "ThinkPad" в кошницата си То цената трябва да е 2600
  155. OH HAI: I CAN BAI STUFF SO WE CAN HAZ

    MONEYZ N00BZ SHOULD BAI STUFF MISHUN: BAI STUFF CHEAPER I CAN HAS CHEEZEBURGERS: | NAME | MONEYZ | | MacBook Air | 2000 | | ThinkPad | 1000 | WEN I AD 1 "MacBook Air" TO MAI BASKET AN I AD 1 "ThinkPad" TO MAI BASKET DEN I SHOULD PAY 2600
  156. Steak

  157. Cucumber с Ruby вместо Gherkin

  158. feature 'Main page' do background do create_user :login => 'jdoe'

    end scenario 'should show existing quotes' do create_quote :text => 'The language of friendship', :author => 'Henry David Thoreau' login_as 'jdoe' visit '/' within('.quote') do page.should have_content('The language of friendship') page.should have_content('Henry David Thoreau') end end end
  159. Има смисъл, когато само програмисти работят с acceptance тестовете.

  160. Factory Girl

  161. FactoryGirl.define do factory :user do sequence(:email) { |n| "person-#{n}@example.org" }

    sequence(:faculty_number) { |n| "%05d" % n } full_name 'John Doe' end factory :admin, parent: :user do admin true end factory :topic do title 'Title' body 'Body' user end # ... end
  162. FactoryGirl.create :user, name: 'Stefan'

  163. Rspec-Mocks Mocha FlexMock rr

  164. AutoTest Watchr Guard

  165. 1. Защо пишем тестове? 2. Структура и понятия 3. Често

    срещани грешки 4. Инструменти в Ruby 5. Test-Driven Development 6. Mocks 7. Behavior-Driven Development
  166. объркващи понятия

  167. None
  168. Моят браузър е Гугъл, бабиното.

  169. Правя Test-Driven Development.

  170. Правя Test-Driven Development. Пиша тестове.

  171. test-driven development automated testing

  172. Инструмент Автоматизирани тестове

  173. Подход Test-Driven Development Test-Driven Development

  174. “Test-Driven Development is not about testing” — Dan North

  175. дизайн

  176. TDD = Test-Driven Design

  177. на практика

  178. Добавяте тест 1 ...за несъществуващ код Пишете код 2 ...колкото

    тестът да мине Правите подобрения 3 ...докато премахнете повторенията
  179. Добавяте тест 1 ...за несъществуващ код Пишете код 2 ...колкото

    тестът да мине Правите подобрения 3 ...докато премахнете повторенията
  180. Добавяте тест 1 ...за несъществуващ код Пишете код 2 ...колкото

    тестът да мине Правите подобрения 3 ...докато премахнете повторенията • Тествате кода, който бихте искали да имате • Няма да се компилира (липсващи методи/класове) • Пускате го и гледате как се проваля • Имате червен тест проверяващ функционалността
  181. Добавяте тест 1 ...за несъществуващ код Пишете код 2 ...колкото

    тестът да мине Правите подобрения 3 ...докато премахнете повторенията • Добавяте достатъчно код за да мине теста • Нито ред повече • Най-простото решение, което ви хрумва • Имате работещ код и зелен тест, който го потвърждава
  182. Добавяте тест 1 ...за несъществуващ код Пишете код 2 ...колкото

    тестът да мине Правите подобрения 3 ...докато премахнете повторенията • Не добавяте функционалност • Подобрявате кода/дизайна • Премахвате повторенията • На всяка стъпка пускате теста
  183. 1 2 3 TDD =

  184. четвъртата стъпка

  185. Прочитате съобщението 1.5 ...и се уверявате, че е достатъчно информативно

  186. пример

  187. Disclaimer

  188. 1 2 3 Кодът, който искате да describe "Message" do

    it "should support initialization" do message = Message.new('fry@foo.bg', 'bender@foo.bg', 'Hi!') message.from.should == 'fry@foo.bg' message.to.should == 'bender@foo.bg' message.title.should == 'Hi!' end end F 1) NameError in 'Message should support initialization' uninitialized constant Message /work/message/spec/message_spec.rb:5: Finished in 0.009336 seconds 1 example, 1 failure
  189. 1 2 3 Най-простата имплементация class Message attr_reader :from, :to,

    :title def initialize(from, to, title) @from = from @to = to @title = title end end . Finished in 0.009999 seconds 1 example, 0 failures
  190. 1 2 3 Пас class Message attr_reader :from, :to, :title

    def initialize(from, to, title) @from = from @to = to @title = title end end Всичко изглежда ок, няма нужда от рефакториране
  191. 1 2 3 Изразявате новата функционалност в describe 'Message' do

    # ... it "should validate 'from'" do # bacon.should be_valid 㱻 assert bacon.valid? Message.new('fry@foo.bg', 'bender@foo.bg', 'Hi!').should be_valid Message.new('foo.bg', 'bender@foo.bg', 'Hi!').should_not be_valid Message.new('fry@foo', 'bender@foo.bg', 'Hi!').should_not be_valid end end .F 1) NoMethodError in 'Message should validate 'from'' undefined method `valid?' for #<Message:0x100327e08> /work/message/spec/message_spec.rb:13: Finished in 0.010847 seconds 2 examples, 1 failure
  192. 1 2 3 Прост регулярен израз class Message attr_reader :from,

    :to, :title def initialize(from, to, title) @from = from @to = to @title = title end def valid? @from =~ /^[a-z]+@[a-z]+(\.[a-z]+)+$/ end end .. Finished in 0.011689 seconds 2 examples, 0 failures
  193. 1 2 3 Отново пас class Message attr_reader :from, :to,

    :title def initialize(from, to, title) @from = from @to = to @title = title end def valid? @from =~ /^[a-z]+@[a-z]+(\.[a-z]+)+$/ end end Все още всичко е ОК
  194. 1 2 3 Отново, почвате с тест преди кода describe

    'Message' do # ... it "should validate 'to'" do Message.new('fry@foo.bg', 'bender@foo.bg', 'Hi!').should be_valid Message.new('fry@foo.bg', 'bender', 'Hi!').should_not be_valid Message.new('fry@foo.bg', 'bender@foo', 'Hi!').should_not be_valid end end ..F 1) 'Message should validate 'to'' FAILED expected valid? to return false, got 0 /work/message/spec/message_spec.rb:20: Finished in 0.009825 seconds 3 examples, 1 failure
  195. 1 2 3 Най-простата имплементация class Message attr_reader :from, :to,

    :title def initialize(from, to, title) @from = from @to = to @title = title end def valid? @from =~ /^[a-z]+@[a-z]+(\.[a-z]+)+$/ and @to =~ /^[a-z]+@[a-z]+(\.[a-z]+)+$/ end end ... Finished in 0.010058 seconds 3 examples, 0 failures
  196. class Message attr_reader :from, :to, :title def initialize(from, to, title)

    @from = from @to = to @title = title end def valid? @from =~ /^[a-z]+@[a-z]+(\.[a-z]+)+$/ and @to =~ /^[a-z]+@[a-z]+(\.[a-z]+)+$/ end end 1 2 3 Повторение
  197. class Message attr_reader :from, :to, :title def initialize(from, to, title)

    @from = from @to = to @title = title end def valid? @from =~ /^[a-z]+@[a-z]+(\.[a-z]+)+$/ and @to =~ /^[a-z]+@[a-z]+(\.[a-z]+)+$/ end private def email_valid?(address) address =~ /^[a-z]+@[a-z]+(\.[a-z]+)+$/ end end 1 2 3 Малки стъпки ... Finished in 0.010158 seconds 3 examples, 0 failures
  198. class Message attr_reader :from, :to, :title def initialize(from, to, title)

    @from = from @to = to @title = title end def valid? email_valid?(@from) and @to =~ /^[a-z]+@[a-z]+(\.[a-z]+)+$/ end private def email_valid?(address) address =~ /^[a-z]+@[a-z]+(\.[a-z]+)+$/ end end 1 2 3 Ама наистина малки ... Finished in 0.010001 seconds 3 examples, 0 failures
  199. class Message attr_reader :from, :to, :title def initialize(from, to, title)

    @from = from @to = to @title = title end def valid? email_valid?(@from) and email_valid?(@to) end private def email_valid?(address) address =~ /^[a-z]+@[a-z]+(\.[a-z]+)+$/ end end 1 2 3 Готово ... Finished in 0.009903 seconds 3 examples, 0 failures
  200. None
  201. Тестът е пример за интерфейса, който имплементирате

  202. Принуждава ви да измислите дизайн

  203. Дизайнът е основан на обратна връзка, а не на спекулация

  204. гарантира ви че имате тест

  205. None
  206. false positive

  207. гарантира, че кодът е тестваем

  208. sans debugging

  209. Everyone knows that debugging is twice as hard as writing

    a program in the first place. So if you're as clever as you can be when you write it, how will you ever debug it? — Brian Kenighan
  210. Намалява нуждата от debugging почти напълно, понеже работите на малки

    стъпки и знаете кога сте въвели бъга
  211. Scope creep

  212. Y.A.G.N.I. Y! ain’t gonna need it

  213. Ритъм

  214. 1. Защо пишем тестове? 2. Структура и понятия 3. Често

    срещани грешки 4. Инструменти в Ruby 5. Test-Driven Development 6. Mocks 7. Behavior-Driven Development
  215. None
  216. Mock-овете не имплементират поведение, а поставят очаквания къд кода

  217. • Този метод трябва да се извика с тези параметри

    • Този метод не трябва да се извиква Тестовете с mock-ове често поставят очаквания като:
  218. controller specs

  219. describe RegistrationsController do describe "PUT update" do context "when valid"

    do let(:registration) { double } before do Registration.stub :new => registration registration.stub :create => true end it "constructs a Registration with params[:registration]" do registration.should_receive(:new).with('registration data') post :create, registration: 'registration data' end it "creates a registration" do registration.should_receive(:create) post :create end end end end
  220. class RegistrationsController < ApplicationController def create @registration = Registration.new params[:registration]

    if @registration.create redirect_to root_path else render :action => :new end end end
  221. Изглежда, всякаш не тествате нищо съществено. Въпреки това, има предимства.

  222. Mock-овете държат интерфейса между контролер и модел тесен

  223. Тестовете на контролерите са по-бързи и по-точни

  224. Когато пишете теста на контролера, преди да имплементирате модела, правите

    interface discovery
  225. fat model, skinny controller

  226. 1. Защо пишем тестове? 2. Структура и понятия 3. Често

    срещани грешки 4. Инструменти в Ruby 5. Test-Driven Development 6. Mocks 7. Behavior-Driven Development
  227. BDD започва като начин да се пооправи терминологията в света

    на тестването...
  228. ...и успява да я направи още по-объркана. Съкращението BDD не

    се ползва консистентно.
  229. нова терминология

  230. assert ➡ expectation test method ➡ example test case ➡

    example group
  231. example-driven development

  232. прилага идеите на TDD върху feature-ите* на приложението * чуждиците

    не са куул
  233. 1 red red green refactor green refactor 2 3 4

    5 6 7 RSpec Cucumber
  234. Ресурси

  235. None
  236. None
  237. None
  238. None
  239. None
  240. Въпроси

  241. Следващия път

  242. На Васил му писна!