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

JavaScript Testing Tactics ⚡️ Lightning Edition

JavaScript Testing Tactics ⚡️ Lightning Edition

Justin Searls

May 09, 2014
Tweet

More Decks by Justin Searls

Other Decks in Programming

Transcript

  1. #sjsJustin ## background * ⚡️ 20 minutes! ⚡️ * ~~purposes

    of each type of test~~ * ~~integration tests~~
  2. #sjsJustin ## background * ⚡️ 20 minutes! ⚡️ * ~~purposes

    of each type of test~~ * ~~integration tests~~ * ~~frameworks vs. TDD~~
  3. #sjsJustin ## background * ⚡️ 20 minutes! ⚡️ * ~~purposes

    of each type of test~~ * ~~integration tests~~ * ~~frameworks vs. TDD~~ * a handful of situational tactics
  4. #sjsJustin ## background * ⚡️ 20 minutes! ⚡️ * ~~purposes

    of each type of test~~ * ~~integration tests~~ * ~~frameworks vs. TDD~~ * a handful of situational tactics * using Jasmine
  5. #sjsJustin ## background * ⚡️ 20 minutes! ⚡️ * ~~purposes

    of each type of test~~ * ~~integration tests~~ * ~~frameworks vs. TDD~~ * a handful of situational tactics * using Jasmine * generally applicable
  6. #sjsJustin ## background * ⚡️ 20 minutes! ⚡️ * ~~purposes

    of each type of test~~ * ~~integration tests~~ * ~~frameworks vs. TDD~~ * a handful of situational tactics * using Jasmine * generally applicable-ish
  7. #sjsJustin ## background * ⚡️ 20 minutes! ⚡️ * ~~purposes

    of each type of test~~ * ~~integration tests~~ * ~~frameworks vs. TDD~~ * a handful of situational tactics * using Jasmine * generally applicable-ish *ymmv*
  8. #sjsJustin ## syntax ### What I don't do ! *

    use Jasmine's (RSpec-like) DSL
  9. describe("Math", function(){ var subject, result; beforeEach(function(){ subject = new Math();

    }); describe("#add", function(){ beforeEach(function(){ }); }); });
  10. describe("Math", function(){ var subject, result; beforeEach(function(){ subject = new Math();

    }); describe("#add", function(){ beforeEach(function(){ result = subject.add(4,5); }); }); });
  11. describe("Math", function(){ var subject, result; beforeEach(function(){ subject = new Math();

    }); describe("#add", function(){ beforeEach(function(){ result = subject.add(4,5); }); it("adds", function(){ }); }); });
  12. describe("Math", function(){ var subject, result; beforeEach(function(){ subject = new Math();

    }); describe("#add", function(){ beforeEach(function(){ result = subject.add(4,5); }); it("adds", function(){ expect(result).toEqual(9); }); }); });
  13. #sjsJustin ## syntax ### What I don't do ! *

    use Jasmine's (RSpec-like) DSL * write my specs with JavaScript
  14. #sjsJustin ## syntax ### What's the problem? ! * Jasmine

    DSL is not obvious * test code is verbose, unwieldy
  15. #sjsJustin ## syntax ### What's the problem? ! * Jasmine

    DSL is not obvious * test code is verbose, unwieldy * those crying mustaches
  16. #sjsJustin ## syntax ### What's the problem? ! * Jasmine

    DSL is not obvious * test code is verbose, unwieldy * those crying mustaches });
  17. describe("Math", function(){ var subject, result; beforeEach(function(){ subject = new Math();

    }); describe("#add", function(){ beforeEach(function(){ result = subject.add(4,5); }); it("adds", function(){ expect(result).toEqual(9); }); }); });
  18. describe "Math", -> beforeEach -> @subject = new Math() !

    describe "#add", -> beforeEach -> @result = @subject.add(4,5) ! it "adds", -> expect(@result).toEqual(9)
  19. #sjsJustin ## syntax ### What I do ! * write

    specs in CoffeeScript * use the *-given DSL
  20. describe "Math", -> beforeEach -> @subject = new Math() !

    describe "#add", -> beforeEach -> @result = @subject.add(4,5) ! it "adds", -> expect(@result).toEqual(9)
  21. describe "Math", -> Given -> @subject = new Math() !

    describe "#add", -> When -> @result = @subject.add(4,5) Then -> @result == 9
  22. describe("Math", function(){ var subject, result; beforeEach(function(){ subject = new Math();

    }); describe("#add", function(){ beforeEach(function(){ result = subject.add(4,5); }); it("adds", function(){ expect(result).toEqual(9); }); }); });
  23. describe "Math", -> Given -> @subject = new Math() !

    describe "#add", -> When -> @result = @subject.add(4,5) Then -> @result == 9
  24. #sjsJustin ## syntax ### What I do ! * write

    specs in CoffeeScript * use the *-given DSL * jasmine-given ported rspec-given
  25. #sjsJustin ## syntax ### What I do ! * write

    specs in CoffeeScript * use the *-given DSL * jasmine-given ported rspec-given * mocha-given ported jasmine-given
  26. #sjsJustin ## test runner ### What I don't do !

    * default plain HTML test runner
  27. #sjsJustin ## test runner ### What I don't do !

    * default plain HTML test runner * jasmine-maven-plugin
  28. #sjsJustin ## test runner ### What I don't do !

    * default plain HTML test runner * jasmine-maven-plugin * jasmine-rails
  29. #sjsJustin ## test runner ### What I don't do !

    * default plain HTML test runner * jasmine-maven-plugin * jasmine-rails * any server-side-dependent plugin
  30. #sjsJustin ## test runner ### What's the problem? ! *

    feedback isn't fast enough * build tools treat JS as 2nd-class
  31. #sjsJustin ## test runner ### What's the problem? ! *

    feedback isn't fast enough * build tools treat JS as 2nd-class * friction of server-side coupling
  32. #sjsJustin ## test runner ### What I do ! *

    use Testem as my runner * use Lineman to build my code
  33. #sjsJustin ## test runner ### What I do ! *

    use Testem as my runner * use Lineman to build my code * runs tests in < 300ms on each file change
  34. #sjsJustin ### What I don't do ! * start a

    fake server that can stub & verify XHRs ## ajax & ui events
  35. #sjsJustin ### What I don't do ! * start a

    fake server that can stub & verify XHRs * monkey-patch the browser's XHR facilities ## ajax & ui events
  36. #sjsJustin ### What I don't do ! * start a

    fake server that can stub & verify XHRs * monkey-patch the browser's XHR facilities * invoke code by triggering UI events ## ajax & ui events
  37. #sjsJustin ### What's the problem? ! * too integrated for

    unit tests * test pain isn't actionable (e.g. “only mock what you own”) ## ajax & ui events
  38. #sjsJustin ### What's the problem? ! * too integrated for

    unit tests * test pain isn't actionable (e.g. “only mock what you own”) * raises concerns better handled by integrated tests ## ajax & ui events
  39. #sjsJustin ### What's the problem? ! * too integrated for

    unit tests * test pain isn't actionable (e.g. “only mock what you own”) * raises concerns better handled by integrated tests * no pressure to improve private APIs ## ajax & ui events
  40. #sjsJustin ### What I do ! * wrap native/3rd party

    libs with objects I own ## ajax & ui events
  41. #sjsJustin ### What I do ! * wrap native/3rd party

    libs with objects I own * in unit tests, mock wrappers away ## ajax & ui events
  42. #sjsJustin ### What I do ! * wrap native/3rd party

    libs with objects I own * in unit tests, mock wrappers away * test pain? -> improve wrapper API ! ## ajax & ui events
  43. #sjsJustin ### What I do ! * wrap native/3rd party

    libs with objects I own * in unit tests, mock wrappers away * test pain? -> improve wrapper API * wrappers specify our dependence ! ## ajax & ui events
  44. #sjsJustin ### What I do ! * wrap native/3rd party

    libs with objects I own * in unit tests, mock wrappers away * test pain? -> improve wrapper API * wrappers specify our dependence * don’t (typically) test wrappers ## ajax & ui events
  45. #sjsJustin ## asynchronous code ### What I don't do !

    * write async tests for async code
  46. #sjsJustin ## asynchronous code ### What I don't do !

    * write async tests for async code unit ^
  47. #sjsJustin ## asynchronous code ### What's the problem? ! *

    test yields execution control * lots of noise in test setup
  48. #sjsJustin ## asynchronous code ### What's the problem? ! *

    test yields execution control * lots of noise in test setup * speed/timeout concerns
  49. #sjsJustin ## asynchronous code ### What's the problem? ! *

    test yields execution control * lots of noise in test setup * speed/timeout concerns * hard to debug race conditions
  50. #sjsJustin ## asynchronous code ### What's the problem? ! *

    test yields execution control * lots of noise in test setup * speed/timeout concerns * hard to debug race conditions * many reasons for tests to fail
  51. #sjsJustin ## asynchronous code ### What I do ! *

    only write async APIs when useful
  52. #sjsJustin ## asynchronous code ### What I do ! *

    only write async APIs when useful * extract callbacks out of app code and into decorators and mixins
  53. #sjsJustin ## asynchronous code ### What I do ! *

    only write async APIs when useful * extract callbacks out of app code and into decorators and mixins * consider promises over callbacks
  54. #sjsJustin ## asynchronous code ### What I do ! *

    only write async APIs when useful * extract callbacks out of app code and into decorators and mixins * consider promises over callbacks * use jasmine-stealth to capture & discretely test callback functions
  55. #sjsJustin ## the dom ### What I don't do !

    * say "(╯°□°╯ ┻━<table/>━┻" and avoid testing DOM interactions
  56. #sjsJustin ## the dom ### What I don't do !

    * say "(╯°□°╯ ┻━<table/>━┻" and avoid testing DOM interactions * use HTML fixture files
  57. #sjsJustin ## the dom ### What I don't do !

    * say "(╯°□°╯ ┻━<table/>━┻" and avoid testing DOM interactions * use HTML fixture files shared ^
  58. #sjsJustin ## the dom ### What's the problem? #### not

    testing DOM interactions ! * most JavaScript _is_ DOMy UI code
  59. #sjsJustin ## the dom ### What's the problem? #### not

    testing DOM interactions ! * most JavaScript _is_ DOMy UI code * low coverage limits suite's value
  60. #sjsJustin ## the dom ### What's the problem? #### not

    testing DOM interactions ! * most JavaScript _is_ DOMy UI code * low coverage limits suite's value * you'll write *more* DOM-heavy code via path of least resistance
  61. #sjsJustin ## the dom ### What's the problem? #### not

    testing DOM interactions ! * most JavaScript _is_ DOMy UI code * low coverage limits suite's value * you'll write *more* DOM-heavy code via path of least resistance * hampers true outside-in TDD
  62. #sjsJustin ## the dom ### What's the problem? #### using

    HTML fixture files ! * large input -> larger everything !
  63. #sjsJustin ## the dom ### What's the problem? #### using

    HTML fixture files ! * large input -> larger everything * tests should push for small units
  64. #sjsJustin ## the dom ### What's the problem? #### using

    HTML fixture files ! * large input -> larger everything * tests should push for small units * sharing fixtures leads to a "_Tragedy of the Commons_"
  65. #sjsJustin ## the dom ### What I do ! *

    treat the DOM like a 3rd-party dependency, minimizing exposure !
  66. #sjsJustin ## the dom ### What I do ! *

    treat the DOM like a 3rd-party dependency, minimizing exposure * create HTML fixtures inline with jasmine-fixture !
  67. #sjsJustin ## the dom ### What I do ! *

    treat the DOM like a 3rd-party dependency, minimizing exposure * create HTML fixtures inline with jasmine-fixture * arrive at single-purpose DOM-aware functions
  68. #sjsJustin ## less tactically ! Know _why_ you’re testing. !

    Push through the pain before deciding what is worth testing. >
  69. #sjsJustin ## less tactically ! Know _why_ you’re testing. !

    Push through the pain before deciding what is worth testing. ! Easy-to-test code is easy-to-use. Most JavaScript is hard-to-test. ! >
  70. #sjsJustin ## less tactically ! Know _why_ you’re testing. !

    Push through the pain before deciding what is worth testing. ! Easy-to-test code is easy-to-use. Most JavaScript is hard-to-test. ! >
  71. #sjsJustin ## less tactically ! Know _why_ you’re testing. !

    Push through the pain before deciding what is worth testing. ! Easy-to-test code is easy-to-use. Most JavaScript is hard-to-test. ! There’s no Right Way™ in software, just thoughtful and thoughtless approaches. >
  72. #sjsJustin ## Lineman ! ! ! ! ! ! Get

    up and running in minutes! ! * [Docs](http://linemanjs.com) * [Help](http://twitter.com/linemanjs)