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

Chris Hartjes

January 27, 2017
Tweet

More Decks by Chris Hartjes

Other Decks in Technology

Transcript

  1. 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!
  2. Who Should Test? • developers looking for stable deployments •

    developers looking to increase ability to change • developers looking to go home on time
  3. Stable Deployment • Exposes poor deployment practices • Exposes brittle

    application architectures • Promotes “automation-first” thinking
  4. 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?
  5. Confidence In Changes • Removing technical debt is always scary

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

    • Eliminates “stick around just in case” deployments • Makes deployments a non-issue
  7. Design Tool • Tests as working examples of code •

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

    code earlier • Exposes dependencies for code earlier
  9. 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
  10. 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?”
  11. 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
  12. Where Do You Write Tests? • In development environments •

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

    during development • TDD is an incredibly effective design process • Studies have proven it’s effectiveness
  14. 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
  15. 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)
  16. “For just one extra day a week you can have

    90% fewer bugs show up in production!”
  17. 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
  18. 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
  19. 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
  20. 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
  21. 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
  22. 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?
  23. 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
  24. 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
  25. Assertions • Unit tests (usually) usually have one or more

    assertions • Proves that your expectation of an outcome is correct
  26. 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
  27. 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
  28. Constructor Injection • Pass in dependencies at object creation •

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

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

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

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

    not any functionality • Only needs to ‘look like’ the real dependency
  33. 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
  34. Mocks • ‘Stub’ where return value for methods are set

    • Most common test double you will use
  35. 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
  36. 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
  37. 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
  38. Code Kata I • FizzBuzz! • great exercise for covering

    programming basics • easily tested
  39. 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
  40. 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
  41. Data Providers • Reduce the number of tests you write

    • Modify test data sets without modifying test
  42. 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
  43. Code Kata II • Your turn to do some TDD!

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

    • Use data providers • Get into writing code in an iterative way
  45. 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
  46. Test Doubles • Understanding them was the most difficult thing

    I had to learn • Makes you understand how critical putting dependencies in specific states is
  47. 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
  48. 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
  49. 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’
  50. Code Kata IV • Time to tie it all together!

    • Create some doubles • Create some assertions • Write a “working” app the TDD way
  51. 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
  52. 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
  53. 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
  54. Just The Beginning • Learn the basics • Get into

    the TDD rhythm • Dig into other testing tools and techniques