0
Test-Driven JavaScript<br />Eliminating fear and chance from front-end web development<br />
Christian Johansen<br />http://cjohansen.no/<br />http://github.com/cjohansen<br />http://gitorious.org/~cjohansen<br />ht...
My book<br />http://tddjs.com/<br />
What we're doing today<br /><ul><li>How to unit test JavaScript?
JavaScript testing challenges
Tool chain integration</li></li></ul><li>How to unit test JavaScript?<br />
In-browser test frameworks<br />
YUI Test<br /><ul><li>Part of the YUI framework
Can test any code, regardless of framework
In-browser runner
Built-in mocks
Can ship results over the internet
Supports many output formats (JUnit XML, TAP, JSON ++)</li></ul>http://developer.yahoo.com/yui/3/test/<br />
YUI Test case anatomy<br />
YUI Test scaffolding<br />
YUI Test run<br />
YUI Test: The Good<br /><ul><li>Easy to get started
Run in any browser
Built-in mocks
Drop into app for integration testing</li></li></ul><li>YUI Test: The bad<br /><ul><li>Boilerplate HTML fixture
Manually test all browsers</li></li></ul><li>Problem: Impractical workflow<br />
Headless runners<br />
JSpec<br /><ul><li>BDD framework
Runs in browser, Rhino and Node.js
Emulate DOM with env.js
Browser-based: Similar to YUI Test</li></li></ul><li>
JSpec Rhino scaffolding<br />
JSpec Rhino run<br />
JSpec + Rhino: The good<br /><ul><li>No browsers
Fast</li></li></ul><li>Problem: It's all fake<br />
Rhino<br />Just another runtime<br />Not like any browsers actually in use<br />
env.js<br />Just another DOM implementation<br />Not like any DOM implementation in actual use<br />
I hear these are popular<br />
...and these<br />
Manual testing is time consuming<br />
The best from both worlds<br />
JsTestDriver<br />
JsTestDriver.conf<br />
Start JsTestDriver Server<br />java -jar JsTestDriver-1.2.2.jar --port 4224<br />
Capture Target Browsers<br />
JsTestDriver Run<br />
Bonus features<br /><ul><li>Alternative assertion frameworks
Supports QUnit, YUI, Jasmine
JUnit XML Output
Coverage plugin</li></li></ul><li>CLI Helper<br />$ gem install jstdutil<br />$ export JSTESTDRIVER_HOME=~/bin/jstestdrive...
Pretty colors<br />
With errors<br />
Also...<br />$ jsautotest<br />Runs affected tests on each save<br />
Eclipse<br />
Eclipse<br />
Eclipse run<br />
IntelliJ IDEA plugin also available<br />
Just released<br />
JavaScript testing challenges<br />
XMLHttpRequest<br /><ul><li>Needs a server responding
Makes tests run slow(er)
Unsuitable for unit tests</li></li></ul><li>Solution: Encapsulate<br /><ul><li>Simple and elegant
Looser coupling
Easy to test</li></li></ul><li>Example: Chat client<br />
Anatomy<br />
onSubmit<br />messageFormController<br />this.view (form)<br />this.model (cometClient)<br />messageListController<br />th...
What's the trick?<br /><ul><li>All network access goes through cometClient
observable supports same API as cometClient
Use observable in tests</li></li></ul><li>What about cometClient?<br />We'll get there<br />
Event Handlers<br /><ul><li>Touch, keyboard, mouse events
Cross-browser issues
Cumbersome to manually fire</li></li></ul><li>onSubmit<br />messageFormController<br />this.view (form)<br />this.model (c...
Submitting message<br />
Solution: Decouple code<br /><ul><li>Simple
Testable
Often makes sense API-wise</li></li></ul><li>
Testing event handlers<br /><ul><li>Verify that setView adds event handler to form element for submit event
Verify that the handler is postMessage, bound to the controller
Test postMessage separately</li></li></ul><li>Stubs and Mocks<br />
Disclaimer: I wrote that<br />http://cjohansen.no/sinon/<br />
Sinon.JS Spies<br /><ul><li>Wraps functions
Does not interrupt normal execution
Logs all calls and related data</li></li></ul><li>Using Sinon.JS spies<br />
sinon.testCase()<br /><ul><li>Automatically verifies mocks
Automatically restores all fakes
Provides useful utilities (more later)</li></li></ul><li>Verify that an event handler was added<br />
Testing the handler<br />
Testing event handlers<br /><ul><li>Verify that setView adds event handler to form element for submit event
Verify that the handler is postMessage, bound to the controller
Test postMessage separately</li></li></ul><li>
Use an ad hoc stub<br />
Integration: Simulate<br />
Testing actual network access<br />Using Sinon.JS<br />
Configure a fake server<br />
Fake JSON response<br />{<br />  "message": [{<br />    "id": 1,<br />    "user": "Johansen",<br />    "message": "oh hai"...
Force fake server to respond<br />
What happened?<br /><ul><li>GET /chat?1283370174112
Fake server recognizes //chat?d+/
this.server.respond(); fakes a response
Upcoming SlideShare
Loading in...5
×

Test-Driven JavaScript Development (JavaZone 2010)

6,559

Published on

My slides from JavaZone 2010. Watch video:

Published in: Technology
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
6,559
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
67
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

Transcript of "Test-Driven JavaScript Development (JavaZone 2010)"

  1. 1. Test-Driven JavaScript<br />Eliminating fear and chance from front-end web development<br />
  2. 2. Christian Johansen<br />http://cjohansen.no/<br />http://github.com/cjohansen<br />http://gitorious.org/~cjohansen<br />http://twitter.com/cjno<br />
  3. 3. My book<br />http://tddjs.com/<br />
  4. 4. What we're doing today<br /><ul><li>How to unit test JavaScript?
  5. 5. JavaScript testing challenges
  6. 6. Tool chain integration</li></li></ul><li>How to unit test JavaScript?<br />
  7. 7. In-browser test frameworks<br />
  8. 8. YUI Test<br /><ul><li>Part of the YUI framework
  9. 9. Can test any code, regardless of framework
  10. 10. In-browser runner
  11. 11. Built-in mocks
  12. 12. Can ship results over the internet
  13. 13. Supports many output formats (JUnit XML, TAP, JSON ++)</li></ul>http://developer.yahoo.com/yui/3/test/<br />
  14. 14. YUI Test case anatomy<br />
  15. 15.
  16. 16. YUI Test scaffolding<br />
  17. 17. YUI Test run<br />
  18. 18. YUI Test: The Good<br /><ul><li>Easy to get started
  19. 19. Run in any browser
  20. 20. Built-in mocks
  21. 21. Drop into app for integration testing</li></li></ul><li>YUI Test: The bad<br /><ul><li>Boilerplate HTML fixture
  22. 22. Manually test all browsers</li></li></ul><li>Problem: Impractical workflow<br />
  23. 23. Headless runners<br />
  24. 24. JSpec<br /><ul><li>BDD framework
  25. 25. Runs in browser, Rhino and Node.js
  26. 26. Emulate DOM with env.js
  27. 27. Browser-based: Similar to YUI Test</li></li></ul><li>
  28. 28. JSpec Rhino scaffolding<br />
  29. 29. JSpec Rhino run<br />
  30. 30. JSpec + Rhino: The good<br /><ul><li>No browsers
  31. 31. Fast</li></li></ul><li>Problem: It's all fake<br />
  32. 32. Rhino<br />Just another runtime<br />Not like any browsers actually in use<br />
  33. 33. env.js<br />Just another DOM implementation<br />Not like any DOM implementation in actual use<br />
  34. 34.
  35. 35.
  36. 36.
  37. 37.
  38. 38.
  39. 39.
  40. 40.
  41. 41.
  42. 42.
  43. 43. I hear these are popular<br />
  44. 44. ...and these<br />
  45. 45. Manual testing is time consuming<br />
  46. 46. The best from both worlds<br />
  47. 47. JsTestDriver<br />
  48. 48. JsTestDriver.conf<br />
  49. 49.
  50. 50. Start JsTestDriver Server<br />java -jar JsTestDriver-1.2.2.jar --port 4224<br />
  51. 51. Capture Target Browsers<br />
  52. 52.
  53. 53.
  54. 54.
  55. 55.
  56. 56.
  57. 57. JsTestDriver Run<br />
  58. 58. Bonus features<br /><ul><li>Alternative assertion frameworks
  59. 59. Supports QUnit, YUI, Jasmine
  60. 60. JUnit XML Output
  61. 61. Coverage plugin</li></li></ul><li>CLI Helper<br />$ gem install jstdutil<br />$ export JSTESTDRIVER_HOME=~/bin/jstestdriver<br />
  62. 62. Pretty colors<br />
  63. 63. With errors<br />
  64. 64. Also...<br />$ jsautotest<br />Runs affected tests on each save<br />
  65. 65. Eclipse<br />
  66. 66. Eclipse<br />
  67. 67. Eclipse run<br />
  68. 68. IntelliJ IDEA plugin also available<br />
  69. 69. Just released<br />
  70. 70. JavaScript testing challenges<br />
  71. 71. XMLHttpRequest<br /><ul><li>Needs a server responding
  72. 72. Makes tests run slow(er)
  73. 73. Unsuitable for unit tests</li></li></ul><li>Solution: Encapsulate<br /><ul><li>Simple and elegant
  74. 74. Looser coupling
  75. 75. Easy to test</li></li></ul><li>Example: Chat client<br />
  76. 76. Anatomy<br />
  77. 77. onSubmit<br />messageFormController<br />this.view (form)<br />this.model (cometClient)<br />messageListController<br />this.view (dl)<br />this.model (cometClient)<br />cometClient<br />
  78. 78. What's the trick?<br /><ul><li>All network access goes through cometClient
  79. 79. observable supports same API as cometClient
  80. 80. Use observable in tests</li></li></ul><li>What about cometClient?<br />We'll get there<br />
  81. 81. Event Handlers<br /><ul><li>Touch, keyboard, mouse events
  82. 82. Cross-browser issues
  83. 83. Cumbersome to manually fire</li></li></ul><li>onSubmit<br />messageFormController<br />this.view (form)<br />this.model (cometClient)<br />messageListController<br />this.view (dl)<br />this.model (cometClient)<br />cometClient<br />
  84. 84. Submitting message<br />
  85. 85. Solution: Decouple code<br /><ul><li>Simple
  86. 86. Testable
  87. 87. Often makes sense API-wise</li></li></ul><li>
  88. 88. Testing event handlers<br /><ul><li>Verify that setView adds event handler to form element for submit event
  89. 89. Verify that the handler is postMessage, bound to the controller
  90. 90. Test postMessage separately</li></li></ul><li>Stubs and Mocks<br />
  91. 91. Disclaimer: I wrote that<br />http://cjohansen.no/sinon/<br />
  92. 92. Sinon.JS Spies<br /><ul><li>Wraps functions
  93. 93. Does not interrupt normal execution
  94. 94. Logs all calls and related data</li></li></ul><li>Using Sinon.JS spies<br />
  95. 95. sinon.testCase()<br /><ul><li>Automatically verifies mocks
  96. 96. Automatically restores all fakes
  97. 97. Provides useful utilities (more later)</li></li></ul><li>Verify that an event handler was added<br />
  98. 98. Testing the handler<br />
  99. 99.
  100. 100. Testing event handlers<br /><ul><li>Verify that setView adds event handler to form element for submit event
  101. 101. Verify that the handler is postMessage, bound to the controller
  102. 102. Test postMessage separately</li></li></ul><li>
  103. 103. Use an ad hoc stub<br />
  104. 104. Integration: Simulate<br />
  105. 105. Testing actual network access<br />Using Sinon.JS<br />
  106. 106. Configure a fake server<br />
  107. 107. Fake JSON response<br />{<br /> "message": [{<br /> "id": 1,<br /> "user": "Johansen",<br /> "message": "oh hai"<br /> }],<br /> "token": "1"<br />}<br />The cometClient format, an array of one new message<br />
  108. 108. Force fake server to respond<br />
  109. 109. What happened?<br /><ul><li>GET /chat?1283370174112
  110. 110. Fake server recognizes //chat?d+/
  111. 111. this.server.respond(); fakes a response
  112. 112. cometClient dispatches canned data</li></li></ul><li>Testing timers<br /><ul><li>setTimeout/setInterval
  113. 113. Causes slow(er) tests
  114. 114. Causes asynchronous tests</li></li></ul><li>Solution: Fake it<br />
  115. 115. Toolchain<br />
  116. 116.
  117. 117. JsTestDriver and Maven<br />http://code.google.com/p/jsd-maven/<br />
  118. 118. XML Pushups<br />
  119. 119.
  120. 120. Can you take one more?<br />
  121. 121.
  122. 122. Continuous Integration<br />
  123. 123. Hudson setup<br /><ul><li>"Free-style software project"
  124. 124. Hudson xUnit Plugin</li></li></ul><li>
  125. 125.
  126. 126. java -jar test/JsTestDriver-1.2.2.jar <br /> --config jsTestDriver.conf <br /> --reset <br /> --server http://localhost:4223 <br /> --tests all <br /> --testOutput .<br />
  127. 127. Project overview<br />
  128. 128. Test case<br />
  129. 129. Failed test (IE6)<br />
  130. 130. Risky time: Live demo<br /><ul><li>Add a feature - test first
  131. 131. Autotest
  132. 132. Test with Maven
  133. 133. CI with Hudson
  134. 134. Test in multiple browsers</li></li></ul><li>Feature: @-messages<br />Highlight messages directed at current user<br />
  135. 135. onSubmit<br />messageFormController<br />this.view (form)<br />this.model (cometClient)<br />messageListController<br />this.view (dl)<br />this.model (cometClient)<br />cometClient<br />
  136. 136. Questions?<br />
  137. 137. My book<br />http://tddjs.com/<br />
  138. 138. Thanks for your time!<br /><ul><li>http://cjohansen.no/
  139. 139. http://github.com/cjohansen/
  140. 140. http://gitorious.org/~cjohansen/
  141. 141. http://twitter.com/cjno/
  142. 142. christian@cjohansen.no</li>
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×