"A unit test is a piece of a code (usually a method) that invokes another piece of code and checks the correctness of some assumptions afterward. If the assumptions turn out to be wrong, the unit test has failed. A “unit” is a method or function."
“The Art of Unit Testing” by Roy Osherove
So, once again, unit testing implies checking the working efficiency of a separate piece of code against the anticipated result.
- Webpack is a project module bundler.
- Karma is a runner that helps bring a productive testing environment to developers. The environment being one where you don't have to set up loads of configurations, but rather a place where you can just write the code and get instant feedback from your tests.
- Istanbul is yet another JS code coverage tool that computes statement, line, function and branch coverage with module loader hooks to transparently add coverage when running tests.
These will suffice at the initial stage.
So what do I do with this awesome toolset? You use it to configure the environment!
Setting up your test environment
"You’re building your own maze, in a way, and you might just get lost in it...."
Now you can either copy the entire repository that I’ve prepared specifically for this article or follow me step by step. Going forward, I’ll add links to repository files with their explanation.
Package.json is an important part of work with npm, so you can either copy it from my repository or create it with npm init command. Good old NodeJS will show you what lines to fill out and how.
Now you have an empty folder with a versions control file. Copy all of the required dependencies and scripts from here. Run in console npm install (npm i). Now you have the following magic modules in your folder:
- @types - our analyzer needs it to read and understand Typescript code
- html-loader for webpack
- html-webpack-plugin - our webpack needs it to launch html file, connect all builds and use html file for webpack-dev-server
- istanbul-instrumenter-loader - allows us to use instanbul along with webpack
- jasmine - our test framework
- karma - test launcher
- ts-loader - typescript files loader for webpack
- webpack-dev-server - plugin that allows for building a server within node environment that tracks any changes in project files.
- webpack-merge - plugin allowing for unification of webpack setting (since Object.assign isn’t covered in ES5)
- angular and angular-ui-router
- Angular-mocks - we need this module to catch modules and use DI in test mode.
Now you’re all set as far as required packages. In order to configure webpack, read the documentation and repeat the path of the sources presented here. Do the same with Karma (documentation, config).
Also pay attention to webpack test configuration where we register istanbul-instrumenter post loader that was described above. You exclude node_modules, spec.ts and test.ts files to prevent application from attempting to determine test coverage at the source file where we’ll actually initialize it as well as test coverage of uploaded modules and unit tests themselves. In Karma configuration you only enter test.ts file.
Now you’re ready to move to the final step. Thanks to awesome webpack polyfills, we have the opportunity to find and connect all of the required application source files and our unit tests. In this particular configuration vendor.ts, test.vendor.ts, and app.ts will be your source files. You can definitely change them in your configuration. Also note that typescript will conflict if your Require is missing Context. To avoid this conflict, copy these custom typings. Once again, we need html.d.ts file to be able to upload html files dynamically within the application in Typescript.
It’s up to you how you setup the application. Just open app.ts file and here you go!
Unit test example
I’ve created this small unit test to test an app’s service quality.
A describe block is located at the beginning of each set of unit tests. Once you launch a unit test, you’ll see that describe names all tests with a phrase from the first argument, while second argument is the entire tests body where each test is wrapped with it block that, just like in describe case, gets its name and body.
beforeEach is one of the most important global functions of jasmin for Angular, as it lets you launch modules falsely before each unit test. For this purpose, locate mock in it as was done in index.spec.ts.
Speaking about DI and Angular mocks, I meant receipt of app’s services. In this case, it’s _AppService_ that’s recorded in AppService variable for access to tests.
If you’ve done everything described above, you’ll see a beautiful tree-like list comprised of one unit test and a green message “TOTAL: 1 SUCCESS” right after the launch of npm test in console and configuration. A coverage folder will also be created in the project’s root directory. Having opened index.html file, you’ll see a test coverage visualization. Congrats, you’ve just reached the final point of running a unit test in AngularJS.