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.
What is Testem?
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.
Organization: File and Folder Structure
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
Everything related to testing is in the /test/ folder and everything related to the actual application (at least JavaScript files and templates) is in the /js/ folder. You might want to change this file structure, but you’ll want to make a couple configuration changes in spec-runner.js and testem.yml if you do.
Setting Up Jasmine
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.
First, Testem is able to be configured in a way that it’ll create its own HTML file to run the tests in just by specifying where the source JavaScript files are and where the spec files are. There are two reasons that I create my own HTML file rather than taking that route:
- 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:
1 |
|
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.
1 | require.config({ |
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 push
ing more on. Then we require
the specs and run them.
Configuring Testem
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.
1 | framework: jasmine |
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.
Run It
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 /js/
or /test/
folders and the tests should automatically refresh for you too!
Conclusion
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!