Today I learned… there are [at least] two ways to inject a service into Mocha unit tests using the Chai assertion library and Angular mocks. This is just a little thing, but I’ve seen this difference in a few unit testing tutorials and it confused me the first time I came across it.
In my project I have a service called mealsServer. No need to worry about what it does, for now we’re just testing that it gets injected successfully (in other words, exists).
Service Injection Technique #1:
Here I am declaring mealsServer as a variable and then injecting _mealsServer_ using beforeEach:
var mealsServer;
beforeEach(inject(function(_mealsServer_) {
mealsServer = _mealsServer_;
}));
The underscores are an oddity. The underscores are a little syntax trick that make it possible to use the same name for the injection as we use for the variable. In other words, if we didn’t inject _mealsServer_ wrapped in underscores, then var mealsServer would need a different name. I’m all for keeping names consistent whenever possible, so I’m glad I learned about this.
Service Injection Technique #2:
And here’s an alternative: here I am injecting the mealsServer service as part of the it block:
it('should have a working meals-server service', inject(function(mealsServer) {
expect(mealsServer).to.exist;
}));
I’m still learning the ropes of unit testing, so I’m sure there are advantages/disadvantages to each of these approaches. I’m relying a lot on this tutorial: Testing AngularJS Apps Using Karma to get me started.
Personally, I like injecting the service in the same line of code that relies upon it being there. I think this is neater and will hold up better as this file becomes longer.
For reference’s sake, here’s the complete meals-test.js file below. It’s small right now, but just getting to the point of having (any!) tests run successfully was a several hour endeavor. In this version, I am just testing that my services exist and I’m using technique #2 from above.
I am using Mocha as my testing framework, Chai as my assertion library, and my project (and its tests) get Browserified so the requires as there to ensure the modules can be found. I also use Karma to run the tests and PhantomJS as my headless browser.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| 'use strict';
require('../../../app/js/app.js');
require('angular-mocks');
describe('Testing services', function() {
beforeEach(angular.mock.module('cbmApp'));
it('should pass a simple test: true = true', function() {
expect(true).to.equal(true);
});
it('should have a working meals-server service', inject(function(mealsServer) {
expect(mealsServer).to.exist;
}));
it('should have a working user-factory service', inject(function(userFactory) {
expect(userFactory).to.exist;
}));
it('should have a working file-reader service', inject(function(fileReader) {
expect(fileReader).to.exist;
}));
}); |
'use strict';
require('../../../app/js/app.js');
require('angular-mocks');
describe('Testing services', function() {
beforeEach(angular.mock.module('cbmApp'));
it('should pass a simple test: true = true', function() {
expect(true).to.equal(true);
});
it('should have a working meals-server service', inject(function(mealsServer) {
expect(mealsServer).to.exist;
}));
it('should have a working user-factory service', inject(function(userFactory) {
expect(userFactory).to.exist;
}));
it('should have a working file-reader service', inject(function(fileReader) {
expect(fileReader).to.exist;
}));
});
Whew! Now that that works, it’s onwards to writing more thorough unit tests!