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

Learn To Test Like A Grumpy Programmer

Learn To Test Like A Grumpy Programmer

Slides for my workshop at PHPBenelux 2017

27601bca8f38e75cbcf9d2dc843f0b32?s=128

Chris Hartjes

January 27, 2017
Tweet

Transcript

  1. Learn To Test Like A Grumpy Programmer Chris Hartjes PHPBenelux

    Conference 2017
  2. Who is this guy and why should I listen? •

    Long-time tester • Beard conveys authority • Twitter account is verified • PHP dev since 1998 • Wants to help you get better!
  3. 5 W’s (and one H)

  4. Who Should Test? • developers looking for stable deployments •

    developers looking to increase ability to change • developers looking to go home on time
  5. Stable Deployments AUTOMATE AUTOMATE AUTOMATE

  6. Stable Deployment • Exposes poor deployment practices • Exposes brittle

    application architectures • Promotes “automation-first” thinking
  7. Confidence In Changes • Did that new feature break an

    old one? • Did the refactoring break working code? • Did we miss an opportunity to move forward?
  8. Confidence In Changes • Removing technical debt is always scary

    • Increases reliance on automated systems • Forces thinking about more than just code
  9. Go Home On Time • Production pushes will go smoother

    • Eliminates “stick around just in case” deployments • Makes deployments a non-issue
  10. What Is TDD? • Design Tool • Style Enforcer •

    Hard-to-shake Coding Habit
  11. Design Tool • Tests as working examples of code •

    Forces you to concentrate on interfaces and API’s
  12. Design Tool • Limits work in progress • Exposes awkward

    code earlier • Exposes dependencies for code earlier
  13. Code In A Specific Style • Impossible to build fast-running

    unit tests for tightly-coupled code • Modules of code end up like LEGO bricks • “Ports and Adapters” • Dependencies become crystal clear
  14. You Can’t Go Back • “How do I test this

    thing?” • “How do I use this thing?” • “How can I change this thing without breaking it?”
  15. You Can’t Go Back • You stop using 3rd party

    tools without tests • You start re-evaluating how you build code for others • You pay much more attention to interfaces and API’s
  16. Where Do You Write Tests? • In development environments •

    As part of the NORMAL development process • When not prototyping
  17. Done By Developers • Cheapest time to find bugs is

    during development • TDD is an incredibly effective design process • Studies have proven it’s effectiveness
  18. Not When Prototyping • No need to write tests when

    you are experimenting • Once you’ve committed to the idea then TDD takes over to design interfaces and API’s
  19. Studies Prove It’s Value • 15% to 30% more development

    time • 40% to 90% fewer bugs (http://research.microsoft.com/en-us/groups/ese/nagappan_tdd.pdf)
  20. “For just one extra day a week you can have

    90% fewer bugs show up in production!”
  21. When Are Tests Written? • During initial development of functionality

    • Whenever a bug is reported and needs to be fixed • “Test-after” an anti-pattern but sometimes required
  22. During Initial Development • Tests force you to write code

    in a certain way • Lost opportunity costs are a real thing • Burnout from having to work overtime to fix bugs is a real thing
  23. Test-after Considered Harmful • Tests that are decoupled from the

    act of creating the code are often brittle • Brittle tests are hard to maintain, often randomly failing • Randomly failing tests get ignored
  24. Opportunity Costs X vs. 10X vs. 1000X

  25. Why Write Tests? • TDD encourages modular code with explicit

    dependencies • Refactoring and other sweeping changes impossible to do quickly without tests • Tests are stealth documentation on how to use your code
  26. Modular Code • TDD makes you focus on loosely-coupled code

    because of the focus on dependency management • Tightly-coupled code impossible to test without committing huge resources to “monkey-patching” tools or additional infrastructure • The intent of modular code is very clear
  27. Refactoring Much Easier • How would you check if your

    code works with a newer version of PHP? • How could you check if your code works after massive search-and-replace for PSR-2 fixes • How could you test replacing DB calls with calls to a JSON API?
  28. Tests As Stealth Documentation • “Write tests as if the

    code is already working” • They show which dependencies are necessary • They show how the code is actually used
  29. Building Blocks It’s Like Using Lego

  30. It’s Like Lego! • TDD encourages creating applications by combining

    units together like Legos • Results in loosely-coupled modules • Unit testing tools are no different
  31. Assertions • The backbone of unit testing • Simple to

    understand
  32. Assertions • Unit tests (usually) usually have one or more

    assertions • Proves that your expectation of an outcome is correct
  33. The Simplest Test That Runs

  34. Assertions • $this->assertTrue(<some expression>) • $this->assertFalse(<some expression>) • $this->assertEquals(<value 1>,

    <value 2)
  35. Assertions Those three assertions will cover 99% of your unit

    testing needs
  36. Dependency Injection In Unit Tests • Figure out your dependencies

    • Figure out which ones need to be doubles • “Inject” them for your code-under-test to use
  37. Dependency Injection Techniques • Globally-available containers • Constructor injection •

    Setter injection
  38. Globally-available Containers • Best for legacy code where refactoring to

    injection is difficult • Can use $GLOBALS super global in a pinch • Container / service locator usage very common
  39. Constructor Injection • Pass in dependencies at object creation •

    Gets messy if many dependencies are required • Can lead to __construct() doing too much work
  40. Setter Injection • “Less messy” than using constructors • Refactoring

    to add get/set methods not overly intrusive • Allows overriding of internally-created dependencies
  41. Types Of Test Doubles • Classical definition is that there

    are five types • Dummy objects, test stubs, test spies, test mocks, test fakes
  42. Types Of Test Doubles • PHPUnit-compatible test double tools tend

    to only use three • Dummy objects, test stubs, test mocks
  43. Dummy Object • Stand-in for the real dependency • Does

    not any functionality • Only needs to ‘look like’ the real dependency
  44. Dummy Object $mock = Mockery::mock(‘Grumpy\Foo’);

  45. Stubs • ‘Dummy object’ but with defined methods • Methods

    don’t need to return anything • Satisfies any calls to the dependency where the response doesn’t matter
  46. Stubs $mock = Mockery::mock(‘Grumpy\Foo’); $mock->shouldReceive(‘bar’);

  47. Mocks • ‘Stub’ where return value for methods are set

    • Most common test double you will use
  48. Mocks $mock = Mockery::mock(‘Grumpy\Foo’); $mock->shouldReceive(‘bar’) ->andReturn(false);

  49. Test Doubles Considered Harmful • Be careful to not fall

    in love with test doubles • Having to create too many of them exposes tightly- coupled code
  50. Test Doubles Considered Harmful • Use them when you have

    a dependency that is difficult to use under normal circumstances • Database connections and 3rd party API calls come to mind
  51. Code Kata I • Code katas are small coding exercises

    with known solutions • Designed to turn certain programming practices into “muscle memory” • Concept taken from Asian martial arts
  52. Code Kata I • FizzBuzz! • great exercise for covering

    programming basics • easily tested
  53. Code Kata I • make sure you create a directory

    to do your exercises in • make sure you have Composer installed • make sure you’ve installed PHPUnit using it
  54. FizzBuzz • Take a collection of integers • If the

    integer is divisible by 3, change it to ‘Fizz’ • If the integer is divisible by 5, change it to ‘Buzz’ • If the integer is divisible by 3 and 5, change it to ‘FizzBuzz’ • Otherwise do not change the value
  55. FizzBuzz

  56. FizzBuzz

  57. FizzBuzz

  58. FizzBuzz

  59. FizzBuzz

  60. FizzBuzz

  61. FizzBuzz

  62. FizzBuzz

  63. FizzBuzz

  64. FizzBuzz

  65. FizzBuzz

  66. Data Providers • Reduce the number of tests you write

    • Modify test data sets without modifying test
  67. Data Providers • Modify test method to accept parameters matching

    the data you will provide • Create a method that returns an array of arrays containing data
  68. Data Providers

  69. Data Providers

  70. Data Providers

  71. Code Kata II • Your turn to do some TDD!

    • Create an object that turns arabic numbers into Roman Numerals
  72. Code Kata II • Use TDD to design your class

    • Use data providers • Get into writing code in an iterative way
  73. Code Kata II 1 -> I 2 -> II 3

    -> III 4 -> IV 5 -> V 6 -> VI 7 -> VII 8 -> VIII 9 -> IX 10 -> X 40 -> XL 50 -> L
  74. Test Doubles • Understanding them was the most difficult thing

    I had to learn • Makes you understand how critical putting dependencies in specific states is
  75. Test Doubles • Used as a substitute for the dependencies

    your code need • Set to a specific state depending on the scenario • Understanding Dependency Injection required
  76. Test Doubles In Action • Replacing “real” dependencies with ones

    we place in a specific state • Allows us to write tests for code that speaks to data sources and web services
  77. A Simple Example

  78. A Simple Example

  79. A Simple Example

  80. A Simple Example

  81. Code Kata III • Use TDD to add a method

    called getAllActive() • Uses fetchAll() to get back a data set that includes id, email, and is_active set to 1 or 0 • Have at least 3 records, with 2 active • You must manually filter out records in getAllActive() • return results as array with just ‘id’ and ‘email’
  82. Code Kata III

  83. Code Kata III

  84. Code Kata IV • Time to tie it all together!

    • Create some doubles • Create some assertions • Write a “working” app the TDD way
  85. Code Kata IV • Let’s create WidgetTrend • Hit a

    remote API that gives us the price of various widgets in real time • Store the widget prices in a database
  86. Code Kata IV http://127.0.0.1/api/widget/{name of widget}

  87. Code Kata IV Save info in a table called ‘widgettracker’

    id | name | price | date
  88. Code Kata IV • write a test that uses an

    object that calls the API and then stores the value in the database • you will need a test double for the class that calls the API • you will need a test double for the class that stores information in the database
  89. Code Kata IV • Remember to start off with a

    test that assumes your code is working • Don’t be afraid to explore things until you’ve decided what your code’s interfaces look like. Prototyping is not the time for tests! • Focus on things one test at a time, don’t look ahead to future functionality. Your tests will let you go back and rework things and tell you if you broke something in the process
  90. Just The Beginning • Learn the basics • Get into

    the TDD rhythm • Dig into other testing tools and techniques
  91. Thank you! Question time?