Everyone knows now that unit testing is good and that they should do it, but it’s not exactly simple to get started, but once you’re going, it’s pretty simple and highly valuable. But how do you get started? I’ll show you a great setup for Jasmine to get you up and running with unit testing and doing it with style with Testem. Testem and Jasmine come together to make unit testing fun and simple.
Testem is a command line tool that runs on Node.js (what doesn’t run on Node.js these days?). It allows you to launch unit tests for practically any framework straight from the command line. These tests are then run in every single browser you’ve specified – either through configuration or arguments on the command line.
Once Testem is running and the browsers are launched, every time you save a file, the browsers (known as “launchers” by Testem) will automatically refresh and run all of your tests again. Not only are the results of the testing shown in each of the launchers, Testem provides a clean, tabbed interface within the console to display the results returned from each of the launchers. This means you can keep the browsers in the background and still see all the results of all of the tests. See the image below to see what I mean.
Testem command line interface.
This interface is controlled with the keyboard. You can use the left and right arrows to switch between tabs, and as the note at the bottom of the above screenshot says, you can hit
Enter to rerun the tests or you can quit with
q. You can read more about the keyboard controls and everything else related to Testem at their Github repository. You can also watch a great introduction to Testem, courtesy of Jeffrey Way from Nettuts+, over on the Nettuts+ website.
For right now, all you really need to know is that you can install Testem with NPM:
npm install testem –g. Now you can run
testem straight from the console to start testing.
Now that we have Testem installed, we need to talk about setting up the project to use Testem and Jasmine. I’ve actually got a little repository up on Github with my Jasmine-Testem Boilerplate. You can just clone that repository to get started. I’ll explain a bit about it here first, though. Here’s what the main file structure looks like:
root |- js/ | |- lib/ // All third party scripts | |- models/ // Backbone models | |- routers/ // Backbone Routers | |- templates/ // Underscore/Handlebars templates | |- views/ // Backbone Views | |- app.js // Marionette application | |- config.js // RequireJS configuration | `- main.js // Main file for bootstrapping/starting the app |- test/ | |- helpers/ // Any objects/functions to help with testing | |- lib/ // Jasmine's library files | |- spec/ // All tests | |- index.html // HTML page to open in browser for running tests | `- spec-runner.js // loads tests and configures RequireJS `- testem.yml // Testem configuration
You may see some notes mentioning Backbone and RequireJS. Indeed, this boilerplate is designed to get me up and running with a Backbone.Marionette/TwitterBootstrap/RequireJS application quickly and have it ready to test from the start. Some quick notes: /js/config.js and /test/spec-runner.js both have exactly the same RequireJS configuration in them except:
- spec-runner.js includes a couple path aliases specifically for testing
- spec-runner.js specifies a
baseUrl, which is the /js/ folder
We need to set up the HTML file that runs the Jasmine tests. Within the boilerplate that I mentioned above, everything is already configured, but I would like to explain some of the choices and how things work.
- My applications utilize RequireJS, and I don’t know any other way to get Testem to use RequireJS correctly.
- If we have our own HTML file, we can run the tests without Testem. This is great if a project is cloned to a machine that doesn’t have Testem – or even Node.js – installed. I set things up so that the tests will run just as well with or without Testem.
Let’s take a look at the HTML file closely to see what I’ve done:
This is mostly just normal stuff. If you look at jasmine.css, it’s altered from the standard CSS. I think mine looks nicer, and it also hides all of the individual specs – except failed specs. If you hover your cursor over a suite, all of its specs slide down to reveal the entire list. This shrinks down the amount of space required to list the specs considerably.
My Jasmine CSS. Hover over a suite to see its specs.
The rest of the noteworthy stuff is in the body. First, there is a “sandbox” element. If a unit test requires the use of the DOM, make sure it’s done in here and then cleaned up when you’re done. Next, we pull in the main jasmine.js file, testem.js, and then jasmine-html.js. These three files are loaded outside of RequireJS’s mechanisms for a couple reasons.
- Order matters. RequireJS will run dependent files in the order they are finish downloading, not in the order specified in the array, so we need to make sure we have these in the right order.
- testem.js isn’t always available. This file is made available only when Testem is running the tests and reports the results between the browser and the console. If we tried loading testem.js via RequireJS, then if we opened the HTML file straight in the browser without Testem, it would break and the tests wouldn’t run.
Next we load in require.js, which, due to the
data-main attribute of the
script tag, loads spec-runner.js. So, let’s take a look at spec-runner.js.
There’s a lot to see here. At the top we’re configuring RequireJS. You’ll notice that we set the
baseUrl to the /js/ directory so that the source files will work the same way they did before. Also, we added
urlArgs in there to add a random query string so that we don’t run into any cached files. The rest of the configuration is normal path stuff for the libraries and matches the config.js file found in the js folder, except you’ll see near the bottom of
paths that I also added the spec and helpers folders so that it’s easier to pull those in.
After the configuration we move on to start setting up Jasmine the same way you normally would. Then we have the
specs array. This array holds all the string paths to all of the specs you wish to run. Just keep
pushing more on. Then we
require the specs and run them.
Now we need to configure Testem so it knows what to files to load. Take a look at the testem.yml file in the root directory.
The first thing you’ll notice is that I’m using the YML format instead of JSON. The only reason for that is that I was having difficulties getting the JSON configuration to work on my Windows machine. It seems to have something to do with saving to UTF-8 or something. In any case, when Testem was reading the configuration file, it was finding some extra characters that weren’t actually in the file. If I used Notepad, made the .yml file and explicitly saved it as UTF-8 (instead of the default ANSI), it worked. Otherwise, I kept running into troubles.
Anyway, the first property is
framework. The default is Jasmine, so this isn’t necessary, but I put it in here anyway. Next we have
src_files. This lets Testem know where the source and spec files are. Normally, Testem would just load all of these files up (in the order specified, so the js/ files would be before the test/ files) and put them into the HTML file itself, but since we have our own HTML file, as specified by the next property:
test_page, it just watches these files for changes so it can rerun the tests.
As I said
test_page lets Testem know that we’re using our own HTML page and points Testem to where it is. Finally, we have
launch_in_dev, which controls which launchers are used when you run Testem in your “dev” environment. Check out the docs if you want to know more about these launchers and running tests in environments other than just “dev”. I’m just using Firefox here, but you can easily change this to whatever browser you tend to develop in.
Now’s the fun part: we get to run Testem. In your console, go to the root directory and type in
testem. If you’re using the boilerplate, you should see a really short test suite that passes. Make some changes to any of the files in the
/test/ folders and the tests should automatically refresh for you too!
Testem can make testing a lot more fun, but you still have to get it set up first. I hope this helped a few of you out and maybe even will get someone new onto the unit testing train. If you still need a little more shoving, next week’s article will show you how to write tests with Jasmine, so you won’t have any more excuses. It’s too easy not to try. God Bless and happy coding!