23 May 2013© 2008-2013 Agile Institute. AllRights Reserved.1Unit-Testing YourLegacyJavaScriptRob Myers & Lars ThorupforMil...
23 May 2013© 2008-2013 Agile Institute. AllRights Reserved.2
characterization tests• We don‟t add or change behavior.• We‟re not bug-hunting.• We aim for coverage.• We must see GREEN....
technique:“The Three Questions”• What behavior needs test coverage?• What‟s preventing us from writing atest?• What can we...
MessTrek lab, part 1:list scenarios that need testing• Let‟s focus on game.js.• Look for behavior that needs testing.Write...
technique:separate code from data• It‟s easier to maintain JavaScriptwhen it‟s not mixed up with HTML.• Use „Name Anonymou...
before23 May 2013© 2008-2013 Agile Institute. AllRights Reserved.7<script>$(function() {$(.new_address_form).hide();$(.cou...
after „Name Anonymous Function‟23 May 2013© 2008-2013 Agile Institute. AllRights Reserved.8<script>$(function() {$(.new_ad...
technique:pass globals into the method• It‟s easier to test a JavaScript method‟svarious behaviors when it can operate on ...
before23 May 2013© 2008-2013 Agile Institute. AllRights Reserved.10<script>$(function() {$(.new_address_form).hide();$(.co...
after „Pass Whole Document‟23 May 2013© 2008-2013 Agile Institute. AllRights Reserved.11<script>$(function() {$(.new_addre...
technique:separate behavior from initialization• It‟s easier to test behavior when notcoupled to initialization code.• Use...
before23 May 2013© 2008-2013 Agile Institute. AllRights Reserved.13var openOrderReport = function(output, accountNumber) {...
after „Extract Method‟23 May 2013© 2008-2013 Agile Institute. AllRights Reserved.14var openOrderReport = function(output, ...
technique:mock dependencies• Results (and test performance) often dependheavily on externals, yet we wantfast, predictable...
sinon.js basics23 May 2013© 2008-2013 Agile Institute. AllRights Reserved.16// to stub a behavior, e.g., Math.random()sino...
MessTrek lab, part 2:write a characterization test• Start in (and be inspired by) test/game.test.html• Focus on weapons.• ...
a few rules for part 2• You must not alter (or add to) anything in theUntouchables folder(userInterface.js, sampleclient.h...
23 May 2013© 2008-2013 Agile Institute.All Rights Reserved.19reflection
23 May 2013© 2008-2013 Agile Institute. AllRights Reserved.20lars@zealake.comhttp://www.zealake.com/blog/@larsthorupRob.My...
Upcoming SlideShare
Loading in …5
×

Unit-Testing Your Legacy JavaScript

878 views
762 views

Published on

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
878
On SlideShare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
0
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide
  • This isn’t TDD. But you won’t be able to proceed with TDD without these techniques.If we find a bug, record it: In a bug tracker, or as a story.Not isolation. These are not “unit tests” - These tests can cover as much behavior as possible (though they must still be deterministic and pretty fast). And they don’t have to be pretty!characterization tests should pass.The test is trying to “pin” behavior so we can refactor further.
  • What needs testing?
  • now move the newly named function into a .js fileTODO: one more, where we pass in the DOM element to make it more testable in various circumstances, with various fixtures
  • now move the newly named function into a .js fileTODO: one more, where we pass in the DOM element to make it more testable in various circumstances, with various fixtures
  • What needs testing?
  • What needs testing?
  • Very easyLean on the compiler
  • Under TDD Resources\\JavaScript\\lib
  • Open the MessTrek files and look at them.What needs testing?What’s stopping you?If you get stuck, there is another set of code available, with tests. Read over the tests and become familiar with the techniques used. Note that the code is still very ugly.
  • sampleclient.html depends on Game’s interface, and represents your customer’s UI developers. UserInterface represents some third-party vendor, and you *can’t* change the code!
  • Thank you!
  • Unit-Testing Your Legacy JavaScript

    1. 1. 23 May 2013© 2008-2013 Agile Institute. AllRights Reserved.1Unit-Testing YourLegacyJavaScriptRob Myers & Lars ThorupforMile High Agile 201319 Apr 2013
    2. 2. 23 May 2013© 2008-2013 Agile Institute. AllRights Reserved.2
    3. 3. characterization tests• We don‟t add or change behavior.• We‟re not bug-hunting.• We aim for coverage.• We must see GREEN.23 May 2013© 2008-2013 Agile Institute. AllRights Reserved.3
    4. 4. technique:“The Three Questions”• What behavior needs test coverage?• What‟s preventing us from writing atest?• What can we do about that?23 May 2013© 2008-2013 Agile Institute. AllRights Reserved.4
    5. 5. MessTrek lab, part 1:list scenarios that need testing• Let‟s focus on game.js.• Look for behavior that needs testing.Write a description of as manyscenarios as you can find.• Also record anything you notice thatwill make testing difficult.23 May 2013© 2008-2013 Agile Institute. AllRights Reserved.5
    6. 6. technique:separate code from data• It‟s easier to maintain JavaScriptwhen it‟s not mixed up with HTML.• Use „Name Anonymous Function‟ as afirst step, if necessary.• Then move the function into a .js fileassociated with the .html file.23 May 2013© 2008-2013 Agile Institute. AllRights Reserved.6
    7. 7. before23 May 2013© 2008-2013 Agile Institute. AllRights Reserved.7<script>$(function() {$(.new_address_form).hide();$(.countrySelect).change(function() {$(.new_address_form).hide();var country = $(".countrySelect").val();if (country === "JP") {$(.address_jp).show();}else {$(.address_generic).show();}});});</script>
    8. 8. after „Name Anonymous Function‟23 May 2013© 2008-2013 Agile Institute. AllRights Reserved.8<script>$(function() {$(.new_address_form).hide();$(.countrySelect).change(onCountryChange);});function onCountryChange() {$(.new_address_form).hide();var country = $(".countrySelect").val();if (country === "JP") {$(.address_jp).show();}else {$(.address_generic).show();}}</script>
    9. 9. technique:pass globals into the method• It‟s easier to test a JavaScript method‟svarious behaviors when it can operate on allor part of a document.• First use „Pass Whole Document‟.• Then have your unit tests pass in minimalDOM fragments (by varying <qunit-fixture>as shown earlier) to test discrete behaviors.23 May 2013© 2008-2013 Agile Institute. AllRights Reserved.9
    10. 10. before23 May 2013© 2008-2013 Agile Institute. AllRights Reserved.10<script>$(function() {$(.new_address_form).hide();$(.countrySelect).change(onCountryChange);});function onCountryChange() {$(.new_address_form).hide();var country = $(".countrySelect").val();if (country === "JP") {$(.address_jp).show();}else {$(.address_generic).show();}}</script>
    11. 11. after „Pass Whole Document‟23 May 2013© 2008-2013 Agile Institute. AllRights Reserved.11<script>$(function() {$(.new_address_form).hide();$(.countrySelect).change(function () { onCountryChange(document); });});function onCountryChange(form) {$(.new_address_form’, form).hide();var country = $(".countrySelect”, form).val();if (country === "JP") {$(.address_jp’, form).show();}else {$(.address_generic’, form).show();}}</script>
    12. 12. technique:separate behavior from initialization• It‟s easier to test behavior when notcoupled to initialization code.• Use „Extract Method‟ to preserveexisting interfaces.• You then have a “seam” where youcan test by injecting mocks.23 May 2013© 2008-2013 Agile Institute. AllRights Reserved.12
    13. 13. before23 May 2013© 2008-2013 Agile Institute. AllRights Reserved.13var openOrderReport = function(output, accountNumber) {var account = LunExData.queryAccount(accountNumber);var openOrders =LunExData.queryOrders("open", account, new Date());for (var i = 0; i < openOrders.length; ++i) {var order = openOrders[i];// ...output.Write("Order ...");// ...}}
    14. 14. after „Extract Method‟23 May 2013© 2008-2013 Agile Institute. AllRights Reserved.14var openOrderReport = function(output, accountNumber) {var account = LunExData.queryAccount(accountNumber);var openOrders =LunExData.queryOrders("open", account, new Date());formatOpenOrderReport(output, account, openOrders);}var formatOpenOrderReport =function(output, account, openOrders) {for (var i = 0; i < openOrders.length; ++i) {var order = openOrders[i];// ...output.Write("Order ...");// ...}}
    15. 15. technique:mock dependencies• Results (and test performance) often dependheavily on externals, yet we wantfast, predictable results.• You can easily stub out the behaviors ofdependencies and libraries.• You are then characterizing the particularbehaviors of your code, not external libraries.• To avoid impacting other tests, be sure to undothe stub after each test.23 May 2013© 2008-2013 Agile Institute. AllRights Reserved.15
    16. 16. sinon.js basics23 May 2013© 2008-2013 Agile Institute. AllRights Reserved.16// to stub a behavior, e.g., Math.random()sinon.stub(Math, random, function () { return 0.5; });// to undo the stubMath.random.restore();
    17. 17. MessTrek lab, part 2:write a characterization test• Start in (and be inspired by) test/game.test.html• Focus on weapons.• Use safe, careful refactorings where necessary.• Do as little refactoring as possible.• For now just get one characterization test topass, then let us know you are DONE!• Be sure to read and understand the rules on thenext slide…23 May 2013© 2008-2013 Agile Institute. AllRights Reserved.17
    18. 18. a few rules for part 2• You must not alter (or add to) anything in theUntouchables folder(userInterface.js, sampleclient.html).• You must not alter the results of anything in theUntouchables folder (sampleclient.html).23 May 2013© 2008-2013 Agile Institute. AllRights Reserved.18
    19. 19. 23 May 2013© 2008-2013 Agile Institute.All Rights Reserved.19reflection
    20. 20. 23 May 2013© 2008-2013 Agile Institute. AllRights Reserved.20lars@zealake.comhttp://www.zealake.com/blog/@larsthorupRob.Myers@agileInstitute.comhttp://PowersOfTwo.agileInstitute.com/@agilecoach

    ×