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 from the testing workshop I did at PHP Australia Conference on April 14, 2016

Chris Hartjes

April 14, 2016

Transcript

95 slides
  1. Who is this guy and why should I listen? •

    Long-time tester • Beard conveys authority • 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. Test Doubles • Understanding them was the most difficult thing

    I had to learn • Makes you understand how critical putting dependencies in specific states is
  27. 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
  28. 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
  29. 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
  30. Constructor Injection • Pass in dependencies at object creation •

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

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

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

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

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

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

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

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

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

    • Use data providers • Get into writing code in an iterative way
  47. 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
  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

More Decks by Chris Hartjes

Other Decks in Technology