Upload
lars-thorup
View
6.033
Download
2
Embed Size (px)
DESCRIPTION
While more and more application code move from the back-end to a JavaScript-based front-end, we still need to test this code efficiently. Testing JavaScript is often done using browser automation frameworks, but system-level testing is slow and brittle. Here we present a way to structure your JavaScript application according to the Model-View-Controller (MVC) design pattern and how this enables us to write unit tests for a large part of the application logic, using a testing framework like QUnit. Sample source code available at http://www.zealake.com/public/javascript-unit-testing.zip
Citation preview
Unit Testing in JavaScript with MVC and QUnitLars ThorupZeaLake Software Consulting
June 14, 2011
Who is Lars Thorup?● Software developer
● Coach: Automated testing and other agile practices
● Advisor: Assesses software projects and companies
● Founder and CEO of BestBrains and ZeaLake
Agenda● Sample application under test
● How to use QUnit
● Asynchronuous testing
● How to use Model-View-Controller
● Assumes knowledge about JavaScript
● Assumes knowledge about unit testing
JavaScript must be tested in the browser
Example app: Collaborative Dialog● Front end entirely in JavaScript
● Back end service methods implemented in C#
How do tests look like?● util.test.html
● ok(actual, message)
● equal(actual, expected, message)
● same(actual, expected, message)● deep equivalence
● raises(expected, function, message)
How to modularize tests?● view.test.html
● module(name, fixture)
● all following tests will have this being a newly created fixture object with setup() and teardown() run before and after the test
Testing ajax● svc.test.html
● call expect(number-of-assertions) to verify that callbacks was actually called
● call stop(timeout) before first ajax call
● call start() when test is complete● typically inside ajax callback
● if more than one asynchronous call in one test:● call stop() before each ● call start() in callback of each
Make your JavaScript testable
● MVC design pattern: Model - View - Controller
● Dependency injection
● Isolated testing controller
view model
svc
View● view.js
● injected html● load html page from the server● html becomes directly stylable
● Responsibilities● manipulate html● generate html from templates● dispatch events to listeners● nothing more!
● References● a set of event listeners
(typically the controller)
controller
view model
svc
Controller● controller.js
● Responsibilities● handle all events from the
view● poll model for change events if
relevant● convert events to commands
against the model● repaint strategy● error handling strategy
● References● the model (to execute
commands, polling)● the view (to do repainting)
controller
view model
svc
Model● model.js
● Responsibilities● cache state to minimize round
trips● provide view and controller
with a useful interface of the data model
● References● the service proxy
controller
view model
svc
Service Proxy● svc.js
● Responsibilities● provide a javascript api
mapping of the server api
● References● the physical server via ajax
controller
view model
svc
Testing the view● view.test.js
● Inject● controllerStub● canvas
● Invoke methods
● Assert● canvas● controllerStub
controllerStub
view
test
Testing the controller● controller.test.js
● Inject● viewStub● modelStub
● Invoke methods
● Assert● viewStub● modelStub
controller
viewStub modelStub
test
Testing the model● model.test.js
● Inject● serverStub
● Invoke methods
● Assert● state● serverStub
model
svcStub
test
Testing the service proxy● svc.test.js
● Invoke methods
● Assert● results
svc
test
Callbacks in JavaScript● Ajax means asynchronous
● Server methods become asynchronous● Model methods become asynchronous● To return a value you must supply a callback
● Error handling● Include in every callback
this in JavaScript● Avoid using this in callbacks, since this probably refers to
the object that invokes the callback, not the object that contains the code for the callback.
● Instead use jQuery's $proxy() method● Example: controller.js
Bootstrap● bootstrap() function
● see collabForm.js
● creates model, view and controller and ties them together
● start polling engine (if relevant)
● called by onload or $(document).ready()● see Index.aspx
Run tests on build server● QUnit tests needs to run in a browser
● On WIndows, the browser requires a WinStation● So the build server must be logged on at all times for this to work
● Hard to avoid tests that hang
● Consider running tests manually instead
Testing the backend● Test your webservices
● Use QUnit and assert on the returned JSON● Or use your backend testing tool
Real World Example● WizerPro, in JavaScript, using MVC pattern
Further reading● Documentation
● http://docs.jquery.com/Qunit
● Book● "Test-Driven JavaScript Development", Christian Johansen
● QUnit Presentation● http://benalman.com/talks/unit-testing-qunit.html
Future meetups● TDD coding dojo with C++ and Ruby
● Thursday June 24th (in a week!)
Feedback● Give your evaluation at meetup.com