Lars Thorup presents on unit testing JavaScript applications with the MVC pattern and QUnit testing framework. He discusses testing views, controllers, models, and services. The document recommends setting up tests for each component in isolation by injecting stubs for their dependencies. Asynchronous testing is also covered, including techniques like stopping/starting to synchronize async calls in tests. The MVC pattern with dependency injection is advocated to make the code more modular and testable.
Injustice - Developers Among Us (SciFiDevCon 2024)
Unit Testing in JavaScript with MVC and QUnit
1. Unit Testing in JavaScript with MVC and QUnit
Lars Thorup
ZeaLake Software Consulting
June 14, 2011
2. 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
3. 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
5. Example app: Collaborative Dialog
● Front end entirely in JavaScript
● Back end service methods implemented in C#
6. 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)
7. 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
8. 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
9. Make your JavaScript testable
● MVC design pattern: Model - View - Controller
● Dependency injection
● Isolated testing controller
view model
svc
10. View
● view.js
controller
● injected html
● load html page from the server
● html becomes directly stylable view model
● Responsibilities
svc
● manipulate html
● generate html from templates
● dispatch events to listeners
● nothing more!
● References
● a set of event listeners
(typically the controller)
11. Controller
● controller.js
controller
● Responsibilities
● handle all events from the
view model
view
● poll model for change events if
relevant svc
● convert events to commands
against the model
● repaint strategy
● error handling strategy
● References
● the model (to execute
commands, polling)
● the view (to do repainting)
12. Model
● model.js
controller
● Responsibilities
● cache state to minimize round
view model
trips
● provide view and controller
with a useful interface of the svc
data model
● References
● the service proxy
13. Service Proxy
● svc.js
controller
● Responsibilities
● provide a javascript api
view model
mapping of the server api
● References svc
● the physical server via ajax
16. Testing the model
● model.test.js test
● Inject
● serverStub
model
● Invoke methods
● Assert
svcStub
● state
● serverStub
17. Testing the service proxy
● svc.test.js test
● Invoke methods
● Assert
● results
svc
18. 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
19. 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
20. 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
21. 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
22. Testing the backend
● Test your webservices
● Use QUnit and assert on the returned JSON
● Or use your backend testing tool