SlideShare a Scribd company logo
Антипаттерны
модульного тестирования




 Митин Павел, RubyConfUa 2010
О себе

• Ruby on Rails разработчик
• 4 года практики в стиле test-driven development
• http://novembermeeting.blogspot.com
Indented test code vs Правило Шапокляк

describe PopularityCalculator, '#popular?' do
  it 'should take into account 
      the comment count' do
    subject.popular?(post).should be_false
  end

  # ...
end
Indented test code vs Правило Шапокляк

class PopularityCalculator
  def popular?(post)
  end
end
Indented test code vs Правило Шапокляк

it 'should take into account the comment count' do
  posts = (0..19).map do |n|
    post_with_comment_count n
  end

  posts.each do |post|
    if 10 < post.comment_count
      subject.popular?(post).should be_true
    else
      subject.popular?(post).should be_false
    end
  end
end
Indented test code vs Правило Шапокляк

class PopularityCalculator
  THRESHOLD = 10

  def popular?(post)
    THRESHOLD < post.comment_count
  end
end
Indented test code vs Правило Шапокляк

it 'should take into account the comment count' do
  posts = (0..19).map do |n|
    post_with_comment_count n
  end

  posts.each do |post|
    if 10 < post.comment_count
      subject.popular?(post).should be_true
    else
      subject.popular?(post).should be_false
    end
  end
end
Indented test code vs Правило Шапокляк

Мотивация:
 • борьба с дублированием
 • работы с неконтролируемыми аспектами
   системы(время, дисковое пространство и т.д.)
Indented test code vs Правило Шапокляк




             Правило Шапокляк:
Это хорошо ... хорошо, что Вы зеленый и плоский
Indented test code vs Правило Шапокляк

it "should return true if the comment count /
    is more then the popularity threshold" do

  post = post_with_comment_count THRESHOLD + 1
  subject.popular?(post).should be_true

  post = post_with_comment_count THRESHOLD + 100
  subject.popular?(post).should be_true
end
Indented test code vs Правило Шапокляк

Бенефиты:
 • тесты проще понять
 • тесты содержат меньше ошибок
Production Logic in Test

class PopularityCalculator
  THRESHOLD = 10

  def popular?(post)
    THRESHOLD < post.comment_count
  end
end
Production Logic in Test

it "should take into account the comment count" do
  post = post_with_comment_count 11
  expected = THRESHOLD < post.comment_count
  actual = subject.popular? post
  actual.should == expected
end
Production Logic in Test

it "should take into account the comment count" do
  post = post_with_comment_count 11
  expected = THRESHOLD < post.comment_count
  actual = subject.popular? post
  actual.should == expected
end
Production Logic in Test

Мотивация: упростить получение ожидаемого значения
Production Logic in Test
Production Logic in Test

it "should take into account the comment count" do
  actual = subject.popular? post_with_comment_count(11)
  actual.should be_true
end
Production Logic in Test

Бенефиты: мы действительно тестируем, а не только
улучшаем тестовое покрытие :)
Too Many Expectations

describe NotificationService, "#notify_about" do
  it "should notify the post author by email" do
    notification_service.notify_about @comment
  end

  it "should notify the post author by sms"
end
Too Many Expectations

class NotificationService <
  Struct.new(:email_service, :sms_service)

  def notify_about(comment)
  end
end
Too Many Expectations

before do
  @email_service, @sms_service = mock, mock
  @comment = Comment.new 'some text', 'dummy post'
  @notification_service = NotificationService.
    new @email_service, @sms_service
end
Too Many Expectations

it "should notify the post author by email" do
  @email_service.expects(:deliver_new_comment_email).
    with @comment
  @sms_service.expects :deliver_new_comment_sms
  @notification_service.notify_about @comment
end Too Many Expectations


it "should notify the post author by sms" do
  @email_service.expects :deliver_new_comment_email
  @sms_service.expects(:deliver_new_comment_sms).
    with @comment
  @notification_service.notify_about @comment
end
Too Many Expectations

def notify_about(comment)
  email_service.deliver_new_comment_email comment
  sms_service.deliver_new_comment_sms comment
end
Too Many Expectations

it "should notify the post author by email" do
  @email_service.expects(:deliver_new_comment_email).
    with @comment
  @sms_service.expects :deliver_new_comment_sms
  @notification_service.notify_about @comment
end

it "should notify the post author by sms" do
  @email_service.expects :deliver_new_comment_email
  @sms_service.expects(:deliver_new_comment_sms).
    with @comment
  @notification_service.notify_about @comment
end
Too Many Expectations

def notify_about(comment)
  # email_service.deliver_new_comment_email comment
  sms_service.deliver_new_comment_sms comment
end
Too Many Expectations

1)
Mocha::ExpectationError in 'NotificationService#notify_about should notify the post author by email'
not all expectations were satisfied
unsatisfied expectations:
- expected exactly once, not yet invoked: #<Mock:0xb74cdd64>.deliver_new_comment_email(#<Comment:0xb74cdb70>,
#<Mock:0xb74cdf08>)
satisfied expectations:
- expected exactly once, already invoked once: #<Mock:0xb74cde2c>.get(any_parameters)
- expected exactly once, already invoked once: #<Mock:0xb74cdc9c>.author_id(any_parameters)
- expected exactly once, already invoked once: nil.deliver_new_comment_sms(any_parameters)




2)
Mocha::ExpectationError in 'NotificationService#notify_about should notify the post author by sms'
not all expectations were satisfied
unsatisfied expectations:
- expected exactly once, not yet invoked: #<Mock:0xb74c937c>.deliver_new_comment_email(any_parameters)
satisfied expectations:
- expected exactly once, already invoked once: #<Mock:0xb74c9444>.get(any_parameters)
- expected exactly once, already invoked once: #<Mock:0xb74c92b4>.author_id(any_parameters)
- expected exactly once, already invoked once: nil.deliver_new_comment_sms(#<Comment:0xb74c9188>,
#<Mock:0xb74c9520>)
Too Many Expectations
Too Many Expectations

Причины воспроизведения паттерна: отсутствие
знаний о стаб-объектах
Too Many Expectations

before do
  @sms_service = stub_everything
  @email_service = stub_everything


  @notification_service = NotificationService.
    new @email_service, @sms_service
end
Too Many Expectations

it "should notify the post author by email" do
  @email_service.expects(:deliver_new_comment_email).
    with @comment, @author
 @notification_service.notify_about @comment
end

it "should notify the post author by sms" do
  @sms_service.expects(:deliver_new_comment_sms).
    with @comment, @author
  @notification_service.notify_about @comment
end
Too Many Expectations

Бенефиты: одна ошибка - один падающий тест
Redundant Fixture

describe PostRepository, "#popular" do
  it "should return all popular posts" do
    repository.popular.should include(popular_post)
  end
end
Redundant Fixture

class PostRepository
  def popular
    []
  end
end
Redundant Fixture

it "should return all popular posts" do
  popular_posts = (1..2).map { build_popular_post }
  unpopular_posts = (1..3).
    map { build_unpopular_post }
  posts = (popular_posts + unpopular_posts).shuffle
  repository = PostRepository.new posts

  actual = repository.popular

  actual.should have(2).posts
  actual.should include(popular_posts.first,
                        popular_posts.last)
end
Redundant Fixture

it "should return all popular posts" do
  popular_posts = (1..2).map { build_popular_post }
  unpopular_posts = (1..3).
    map { build_unpopular_post }
  posts = (popular_posts + unpopular_posts).shuffle
  repository = PostRepository.new posts

  actual = repository.popular

  actual.should have(2).posts
  actual.should include(popular_posts.first,
                        popular_posts.last)
end
Redundant Fixture

Мотивация: желание получить в тестовом окружении
“реальные” данные
Redundant Fixture




       VS
Redundant Fixture

before do
  @popular_post = build_popular_post
  @unpopular_post = build_unpopular_post
  @repository = PostRepository.new(
    [@popular_post, @unpopular_post] )
end
it "should return a popular post" do
  @repository.popular.should include(@popular_post)
end
it "shouldn't return an unpopular post" do
  @repository.popular.
    should_not include(@unpopular_post)
end
Redundant Fixture

Бенефиты:
 • простой setup
 • сообщение о падении теста не перегружено лишними
   данными
 • профилактика "медленных" тестов
Neglected Diagnostic vs Ясный красный

describe BullshitProfitCalculator, "#calculate" do
  it "should return the projected profit" do
    actual = subject.calculate 'dummy author'
    actual.should == '$123'.to_money
  end
end

class BullshitProfitCalculator
  def calculate(author)
    '$1'.to_money
  end
end
Neglected Diagnostic vs Ясный красный

'BullshitProfitCalculator#calculate should return the projected
profit' FAILED
expected: #<Money:0xb7447ebc @currency=#<Money::Currency id: usd
priority: 1, iso_code: USD, name: United States Dollar, symbol: $,
subunit: Cent, subunit_to_unit: 100, separator: ., delimiter: ,>,
@cents=12300, @bank=#<Money::VariableExchangeBank:0xb74dabb8
@rates={}, @mutex=#<Mutex:0xb74dab7c>, @rounding_method=nil>>,
    got: #<Money:0xb7448038 @currency=#<Money::Currency id: usd
priority: 1, iso_code: USD, name: United States Dollar, symbol: $,
subunit: Cent, subunit_to_unit: 100, separator: ., delimiter: ,>,
@cents=100, @bank=#<Money::VariableExchangeBank:0xb74dabb8 @rates={},
@mutex=#<Mutex:0xb74dab7c>, @rounding_method=nil>> (using ==)
Neglected Diagnostic vs Ясный красный
Neglected Diagnostic vs Ясный красный

module TestMoneyFormatter
  def inspect
    format
  end
end

class Money
  include TestMoneyFormatter
end
Neglected Diagnostic vs Ясный красный

'BullshitProfitCalculator#calculate should return
the projected profit' FAILED
expected: $123.00,
     got: $1.00 (using ==)
Neglected Diagnostic vs Ясный красный

Было:                 Стало:
красный               красный
                      ясный красный
зеленый               зеленый
рефакторинг           рефакторинг
Neglected Diagnostic vs Ясный красный

Бенефиты: ясное диагностическое сообщение упрощает
дальнейшую поддержку теста
Еще антипаттерны

• глобальные фикстуры
• функциональный код, используемый только в тестах
• нарушение изоляции тестов
• зависимости из других слоев приложения
• тестирование кода фреймворка
Антипаттерны в mocking TDD

• мокание методов тестируемого модуля
• мокание объектов-значений
Еще антипаттерны

• “медленные” тесты
• …
Рекомендуемая литература




• Экстремальное программирование. Разработка
  через тестирование, Кент Бек
• Growing Object-Oriented Software, Guided by Tests
  by Steve Freeman and Nat Pryce
Исходный код примеров

http://github.com/MitinPavel/test_antipatterns.git
Использованные изображения

• http://dreamworlds.ru/kartinki/27030-otricatelnye-
  personazhi-v-multfilmakh.html
• http://www.inquisitr.com/39089/former-police-officer-
  sues-for-discrimination-over-his-alcoholism-disability/
• http://teachpro.ru/source/obz11/Html/der11163.htm
• http://bigpicture.ru/?p=4302
• http://giga.satel.com.ua/index.php?newsid=25654
Спасибо за внимание




 RubyConfUa 2010

More Related Content

PDF
Factory Girl
PPTX
Why you should be using the shiny new C# 6.0 features now!
PDF
focuslight-validator validate sinatra application - validation night at LINE ...
PDF
Effective Java with Groovy - How Language Influences Adoption of Good Practices
PPT
Ruby on Rails testing with Rspec
PDF
Two Trains and Other Refactoring Analogies
ODT
Streaming twitter data using kafka
PDF
Currying and Partial Function Application (PFA)
Factory Girl
Why you should be using the shiny new C# 6.0 features now!
focuslight-validator validate sinatra application - validation night at LINE ...
Effective Java with Groovy - How Language Influences Adoption of Good Practices
Ruby on Rails testing with Rspec
Two Trains and Other Refactoring Analogies
Streaming twitter data using kafka
Currying and Partial Function Application (PFA)

What's hot (20)

KEY
Small pieces loosely joined
PDF
RSpec 3: The new, the old, the good
DOCX
oracle soa Examples
PDF
ActiveRecord Query Interface (2), Season 2
PDF
Why Your Test Suite Sucks - PHPCon PL 2015
DOCX
Getting Started with Maven and Cucumber in Eclipse
PPTX
Rspec 101
PDF
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
ODP
Introduction to Angular js
PDF
Finding the Right Testing Tool for the Job
PDF
JavaScript Refactoring
PPTX
Java script – basic auroskills (2)
PDF
Frontin like-a-backer
KEY
Actions filters
PDF
Spock
KEY
How To Test Everything
PPTX
WordPress Hooks Action & Filters
PPTX
Typescript barcelona
PPTX
Guice gin
PPTX
Sapphire Gimlets
Small pieces loosely joined
RSpec 3: The new, the old, the good
oracle soa Examples
ActiveRecord Query Interface (2), Season 2
Why Your Test Suite Sucks - PHPCon PL 2015
Getting Started with Maven and Cucumber in Eclipse
Rspec 101
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
Introduction to Angular js
Finding the Right Testing Tool for the Job
JavaScript Refactoring
Java script – basic auroskills (2)
Frontin like-a-backer
Actions filters
Spock
How To Test Everything
WordPress Hooks Action & Filters
Typescript barcelona
Guice gin
Sapphire Gimlets
Ad

Viewers also liked (6)

PDF
Backbone.js Профилактика сколиоза
PDF
Hypermedia api (HATEOAS)
PPTX
Сидристый Станислав: Паттерны и антипаттерны BDD
PDF
PageObject
PDF
Command Query Responsibility Segregation and Event Sourcing
PDF
Взаимодействие сервисов через Advanced Message
 Queuing Protocol
Backbone.js Профилактика сколиоза
Hypermedia api (HATEOAS)
Сидристый Станислав: Паттерны и антипаттерны BDD
PageObject
Command Query Responsibility Segregation and Event Sourcing
Взаимодействие сервисов через Advanced Message
 Queuing Protocol
Ad

Similar to Антипаттерны модульного тестирования (20)

PDF
Controller Testing: You're Doing It Wrong
KEY
Ruby/Rails
PDF
PPTX
Python Homework Help
KEY
Tdd for BT E2E test community
PDF
Min-Maxing Software Costs - Laracon EU 2015
KEY
Why ruby
PDF
PDF
How to Write Better Code with Mutation Testing
PDF
Testing web APIs
PDF
RSpock Testing Framework for Ruby
ODP
Advanced Perl Techniques
PDF
Testing in Django
PDF
Getting Answers to Your Testing Questions
PDF
Why Our Code Smells
KEY
Uses & Abuses of Mocks & Stubs
KEY
Testing Has Many Purposes
PDF
Droidcon ES '16 - How to fail going offline
PDF
The First C# Project Analyzed
PDF
Model of the colossus @ Rupy Brazil 2013
Controller Testing: You're Doing It Wrong
Ruby/Rails
Python Homework Help
Tdd for BT E2E test community
Min-Maxing Software Costs - Laracon EU 2015
Why ruby
How to Write Better Code with Mutation Testing
Testing web APIs
RSpock Testing Framework for Ruby
Advanced Perl Techniques
Testing in Django
Getting Answers to Your Testing Questions
Why Our Code Smells
Uses & Abuses of Mocks & Stubs
Testing Has Many Purposes
Droidcon ES '16 - How to fail going offline
The First C# Project Analyzed
Model of the colossus @ Rupy Brazil 2013

Антипаттерны модульного тестирования

  • 2. О себе • Ruby on Rails разработчик • 4 года практики в стиле test-driven development • http://novembermeeting.blogspot.com
  • 3. Indented test code vs Правило Шапокляк describe PopularityCalculator, '#popular?' do it 'should take into account the comment count' do subject.popular?(post).should be_false end # ... end
  • 4. Indented test code vs Правило Шапокляк class PopularityCalculator def popular?(post) end end
  • 5. Indented test code vs Правило Шапокляк it 'should take into account the comment count' do posts = (0..19).map do |n| post_with_comment_count n end posts.each do |post| if 10 < post.comment_count subject.popular?(post).should be_true else subject.popular?(post).should be_false end end end
  • 6. Indented test code vs Правило Шапокляк class PopularityCalculator THRESHOLD = 10 def popular?(post) THRESHOLD < post.comment_count end end
  • 7. Indented test code vs Правило Шапокляк it 'should take into account the comment count' do posts = (0..19).map do |n| post_with_comment_count n end posts.each do |post| if 10 < post.comment_count subject.popular?(post).should be_true else subject.popular?(post).should be_false end end end
  • 8. Indented test code vs Правило Шапокляк Мотивация: • борьба с дублированием • работы с неконтролируемыми аспектами системы(время, дисковое пространство и т.д.)
  • 9. Indented test code vs Правило Шапокляк Правило Шапокляк: Это хорошо ... хорошо, что Вы зеленый и плоский
  • 10. Indented test code vs Правило Шапокляк it "should return true if the comment count / is more then the popularity threshold" do post = post_with_comment_count THRESHOLD + 1 subject.popular?(post).should be_true post = post_with_comment_count THRESHOLD + 100 subject.popular?(post).should be_true end
  • 11. Indented test code vs Правило Шапокляк Бенефиты: • тесты проще понять • тесты содержат меньше ошибок
  • 12. Production Logic in Test class PopularityCalculator THRESHOLD = 10 def popular?(post) THRESHOLD < post.comment_count end end
  • 13. Production Logic in Test it "should take into account the comment count" do post = post_with_comment_count 11 expected = THRESHOLD < post.comment_count actual = subject.popular? post actual.should == expected end
  • 14. Production Logic in Test it "should take into account the comment count" do post = post_with_comment_count 11 expected = THRESHOLD < post.comment_count actual = subject.popular? post actual.should == expected end
  • 15. Production Logic in Test Мотивация: упростить получение ожидаемого значения
  • 17. Production Logic in Test it "should take into account the comment count" do actual = subject.popular? post_with_comment_count(11) actual.should be_true end
  • 18. Production Logic in Test Бенефиты: мы действительно тестируем, а не только улучшаем тестовое покрытие :)
  • 19. Too Many Expectations describe NotificationService, "#notify_about" do it "should notify the post author by email" do notification_service.notify_about @comment end it "should notify the post author by sms" end
  • 20. Too Many Expectations class NotificationService < Struct.new(:email_service, :sms_service) def notify_about(comment) end end
  • 21. Too Many Expectations before do @email_service, @sms_service = mock, mock @comment = Comment.new 'some text', 'dummy post' @notification_service = NotificationService. new @email_service, @sms_service end
  • 22. Too Many Expectations it "should notify the post author by email" do @email_service.expects(:deliver_new_comment_email). with @comment @sms_service.expects :deliver_new_comment_sms @notification_service.notify_about @comment end Too Many Expectations it "should notify the post author by sms" do @email_service.expects :deliver_new_comment_email @sms_service.expects(:deliver_new_comment_sms). with @comment @notification_service.notify_about @comment end
  • 23. Too Many Expectations def notify_about(comment) email_service.deliver_new_comment_email comment sms_service.deliver_new_comment_sms comment end
  • 24. Too Many Expectations it "should notify the post author by email" do @email_service.expects(:deliver_new_comment_email). with @comment @sms_service.expects :deliver_new_comment_sms @notification_service.notify_about @comment end it "should notify the post author by sms" do @email_service.expects :deliver_new_comment_email @sms_service.expects(:deliver_new_comment_sms). with @comment @notification_service.notify_about @comment end
  • 25. Too Many Expectations def notify_about(comment) # email_service.deliver_new_comment_email comment sms_service.deliver_new_comment_sms comment end
  • 26. Too Many Expectations 1) Mocha::ExpectationError in 'NotificationService#notify_about should notify the post author by email' not all expectations were satisfied unsatisfied expectations: - expected exactly once, not yet invoked: #<Mock:0xb74cdd64>.deliver_new_comment_email(#<Comment:0xb74cdb70>, #<Mock:0xb74cdf08>) satisfied expectations: - expected exactly once, already invoked once: #<Mock:0xb74cde2c>.get(any_parameters) - expected exactly once, already invoked once: #<Mock:0xb74cdc9c>.author_id(any_parameters) - expected exactly once, already invoked once: nil.deliver_new_comment_sms(any_parameters) 2) Mocha::ExpectationError in 'NotificationService#notify_about should notify the post author by sms' not all expectations were satisfied unsatisfied expectations: - expected exactly once, not yet invoked: #<Mock:0xb74c937c>.deliver_new_comment_email(any_parameters) satisfied expectations: - expected exactly once, already invoked once: #<Mock:0xb74c9444>.get(any_parameters) - expected exactly once, already invoked once: #<Mock:0xb74c92b4>.author_id(any_parameters) - expected exactly once, already invoked once: nil.deliver_new_comment_sms(#<Comment:0xb74c9188>, #<Mock:0xb74c9520>)
  • 28. Too Many Expectations Причины воспроизведения паттерна: отсутствие знаний о стаб-объектах
  • 29. Too Many Expectations before do @sms_service = stub_everything @email_service = stub_everything @notification_service = NotificationService. new @email_service, @sms_service end
  • 30. Too Many Expectations it "should notify the post author by email" do @email_service.expects(:deliver_new_comment_email). with @comment, @author @notification_service.notify_about @comment end it "should notify the post author by sms" do @sms_service.expects(:deliver_new_comment_sms). with @comment, @author @notification_service.notify_about @comment end
  • 31. Too Many Expectations Бенефиты: одна ошибка - один падающий тест
  • 32. Redundant Fixture describe PostRepository, "#popular" do it "should return all popular posts" do repository.popular.should include(popular_post) end end
  • 33. Redundant Fixture class PostRepository def popular [] end end
  • 34. Redundant Fixture it "should return all popular posts" do popular_posts = (1..2).map { build_popular_post } unpopular_posts = (1..3). map { build_unpopular_post } posts = (popular_posts + unpopular_posts).shuffle repository = PostRepository.new posts actual = repository.popular actual.should have(2).posts actual.should include(popular_posts.first, popular_posts.last) end
  • 35. Redundant Fixture it "should return all popular posts" do popular_posts = (1..2).map { build_popular_post } unpopular_posts = (1..3). map { build_unpopular_post } posts = (popular_posts + unpopular_posts).shuffle repository = PostRepository.new posts actual = repository.popular actual.should have(2).posts actual.should include(popular_posts.first, popular_posts.last) end
  • 36. Redundant Fixture Мотивация: желание получить в тестовом окружении “реальные” данные
  • 38. Redundant Fixture before do @popular_post = build_popular_post @unpopular_post = build_unpopular_post @repository = PostRepository.new( [@popular_post, @unpopular_post] ) end it "should return a popular post" do @repository.popular.should include(@popular_post) end it "shouldn't return an unpopular post" do @repository.popular. should_not include(@unpopular_post) end
  • 39. Redundant Fixture Бенефиты: • простой setup • сообщение о падении теста не перегружено лишними данными • профилактика "медленных" тестов
  • 40. Neglected Diagnostic vs Ясный красный describe BullshitProfitCalculator, "#calculate" do it "should return the projected profit" do actual = subject.calculate 'dummy author' actual.should == '$123'.to_money end end class BullshitProfitCalculator def calculate(author) '$1'.to_money end end
  • 41. Neglected Diagnostic vs Ясный красный 'BullshitProfitCalculator#calculate should return the projected profit' FAILED expected: #<Money:0xb7447ebc @currency=#<Money::Currency id: usd priority: 1, iso_code: USD, name: United States Dollar, symbol: $, subunit: Cent, subunit_to_unit: 100, separator: ., delimiter: ,>, @cents=12300, @bank=#<Money::VariableExchangeBank:0xb74dabb8 @rates={}, @mutex=#<Mutex:0xb74dab7c>, @rounding_method=nil>>, got: #<Money:0xb7448038 @currency=#<Money::Currency id: usd priority: 1, iso_code: USD, name: United States Dollar, symbol: $, subunit: Cent, subunit_to_unit: 100, separator: ., delimiter: ,>, @cents=100, @bank=#<Money::VariableExchangeBank:0xb74dabb8 @rates={}, @mutex=#<Mutex:0xb74dab7c>, @rounding_method=nil>> (using ==)
  • 42. Neglected Diagnostic vs Ясный красный
  • 43. Neglected Diagnostic vs Ясный красный module TestMoneyFormatter def inspect format end end class Money include TestMoneyFormatter end
  • 44. Neglected Diagnostic vs Ясный красный 'BullshitProfitCalculator#calculate should return the projected profit' FAILED expected: $123.00, got: $1.00 (using ==)
  • 45. Neglected Diagnostic vs Ясный красный Было: Стало: красный красный ясный красный зеленый зеленый рефакторинг рефакторинг
  • 46. Neglected Diagnostic vs Ясный красный Бенефиты: ясное диагностическое сообщение упрощает дальнейшую поддержку теста
  • 47. Еще антипаттерны • глобальные фикстуры • функциональный код, используемый только в тестах • нарушение изоляции тестов • зависимости из других слоев приложения • тестирование кода фреймворка
  • 48. Антипаттерны в mocking TDD • мокание методов тестируемого модуля • мокание объектов-значений
  • 50. Рекомендуемая литература • Экстремальное программирование. Разработка через тестирование, Кент Бек • Growing Object-Oriented Software, Guided by Tests by Steve Freeman and Nat Pryce
  • 52. Использованные изображения • http://dreamworlds.ru/kartinki/27030-otricatelnye- personazhi-v-multfilmakh.html • http://www.inquisitr.com/39089/former-police-officer- sues-for-discrimination-over-his-alcoholism-disability/ • http://teachpro.ru/source/obz11/Html/der11163.htm • http://bigpicture.ru/?p=4302 • http://giga.satel.com.ua/index.php?newsid=25654