Jasmine doesn't inject services

2019-08-10 05:34发布

问题:

Premise: my app works perfectly, but anyway I decided to imoplement units tests. My test, that check if a service given object is defined or not fails.

here is my service code:

//app/components/lib/search.js
angular.module("search", ["lazyLoad", "httpInterceptor"])

.service("SearchObject", ['$rootScope', '$location', 'Globals', function ($rootScope, $location, Globals) {
        'use strict';
        var obj,
            SearchObjectPrototype = {};

        SearchObjectPrototype.clone = function (source) {
            var prop;

            for (prop in this) {
                if (this.hasOwnProperty(prop)) {
                    this[prop] = source[prop] || null;
                }
            }
        };

        //Definizione SearchObject
        obj = Object.create(SearchObjectPrototype, {
            q : {value: null, writable: true, enumerable: true},
            max_id : {value: null, writable: true, enumerable: true},
            next_results : {value: null, writable: true, enumerable: true},
            query_debug : {value: null, writable: true, enumerable: true}
        });

        Object.preventExtensions(obj);                      

        this.getInstance = function () {
            return obj;
        };
    }])

Here is my test code:

console.log(1);
describe('search module', function() {
    console.log(2);
    beforeEach(module('search'));

    describe('SearchObject test', function() {
        console.log(3);
        var SearchObject;

        beforeEach(inject(function(_SearchObject_){
            console.log(4);
            // The injector unwraps the underscores (_) from around the parameter names when matching
            SearchObject = _SearchObject_;
        }));

        it('should evaluate the injected SearchObject', function (){
            console.log(5);
            expect(SearchObject).toBeDefined()
        });
    });    
});

Here is my karma.conf.js

// Karma configuration
// http://karma-runner.github.io/0.12/config/configuration-file.html
// Generated on 2015-10-20 using
// generator-karma 1.0.0

module.exports = function(config) {
  'use strict';

  config.set({
    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    // base path, that will be used to resolve files and exclude
    basePath: '../',

    // testing framework to use (jasmine/mocha/qunit/...)
    // as well as any additional frameworks (requirejs/chai/sinon/...)
    frameworks: [
      "jasmine"
    ],

    // list of files / patterns to load in the browser
    files: [
      // bower:js
      'bower_components/jquery/dist/jquery.js',
      'bower_components/angular/angular.js',
      'bower_components/angular-resource/angular-resource.js',
      'bower_components/angular-route/angular-route.js',
      'bower_components/angular-sanitize/angular-sanitize.js',
      'bower_components/angular-touch/angular-touch.js',
      'bower_components/angular-ui-router/release/angular-ui-router.js',
      'bower_components/angular-bootstrap/ui-bootstrap-tpls.js',
      'bower_components/ngInfiniteScroll/build/ng-infinite-scroll.js',
      'bower_components/Chart.js/Chart.js',
      'bower_components/angular-chart.js/dist/angular-chart.js',
      'bower_components/bootstrap-sass/assets/javascripts/bootstrap.js',
      'bower_components/angular-mocks/angular-mocks.js',
      // endbower
      "app/components/lib/search.js",
//      "test/mock/**/*.js",
      "test/spec/search.js"
    ],

    // list of files / patterns to exclude
    exclude: [
    ],

    // web server port
    port: 8080,

    // Start these browsers, currently available:
    // - Chrome
    // - ChromeCanary
    // - Firefox
    // - Opera
    // - Safari (only Mac)
    // - PhantomJS
    // - IE (only Windows)
    browsers: [
      "PhantomJS"
    ],

    // Which plugins to enable
    plugins: [
    "karma-chrome-launcher",
      "karma-phantomjs-launcher",
      "karma-jasmine"
    ],

    // Continuous Integration mode
    // if true, it capture browsers, run tests and exit
    singleRun: false,

    colors: true,

    // level of logging
    // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
    logLevel: config.LOG_INFO,

    // Uncomment the following lines if you are using grunt's server to run the tests
    // proxies: {
    //   '/': 'http://localhost:9000/'
    // },
    // URL root prevent conflicts with the site root
    // urlRoot: '_karma_'
  });
};

Here my Karma output

Running "karma:unit" (karma) task
11 02 2016 11:55:43.447:INFO [karma]: Karma v0.13.19 server started at http://lo
calhost:8080/
11 02 2016 11:55:43.474:INFO [launcher]: Starting browser PhantomJS
11 02 2016 11:55:46.510:INFO [PhantomJS 2.1.1 (Windows 8 0.0.0)]: Connected on s
ocket /#OphIJTNigEfxY1NIAAAA with id 56068342
PhantomJS 2.1.1 (Windows 8 0.0.0) LOG: 1

PhantomJS 2.1.1 (Windows 8 0.0.0) LOG: 2

PhantomJS 2.1.1 (Windows 8 0.0.0) LOG: 3

LOG: 5
PhantomJS 2.1.1 (Windows 8 0.0.0) test sul modulo search SearchObject test shoul
d evaluate the injected SearchObject FAILED
        C:/Users/Rick/Sviluppo/socialsider-fe/bower_components/angular/angular.j
s:4459:53
        forEach@C:/Users/Rick/Sviluppo/socialsider-fe/bower_components/angular/a
ngular.js:340:24
        loadModules@C:/Users/Rick/Sviluppo/socialsider-fe/bower_components/angul
ar/angular.js:4419:12
        createInjector@C:/Users/Rick/Sviluppo/socialsider-fe/bower_components/an
gular/angular.js:4344:22
        workFn@C:/Users/Rick/Sviluppo/socialsider-fe/bower_components/angular-mo
cks/angular-mocks.js:2428:60
        **Expected undefined to be defined.**
        C:/Users/Rick/Sviluppo/socialsider-fe/test/spec/search.js:19:45
PhantomJS 2.1.1 (Windows 8 0.0.0): Executed 1 of 1 (1 FAILED) (0 secs / 0.043 se
PhantomJS 2.1.1 (Windows 8 0.0.0): Executed 1 of 1 (1 FAILED) ERROR (0.019 secs
/ 0.043 secs)

As you can see log(4), which is in the same block of SearchObject assignement, didn't get called. The object is undefined and the test fails.

Anyone can explain me why? It can be a dependency problem?

回答1:

I have found that you need to inject your services/factories yourself:

    beforeEach(function() {
        module('search'));
        inject(function(_SearchObject_) {
            SearchObject = _SearchObject_;
        });
    });

That should make the service available to the tests. I just went back and spot checked some of my own tests and saw that this was the common piece all of my factory and service tests had.

Update: After further review, there are some really odd things going on here and possibly multiple issues that need to be resolved. I don't have all of your dependency libraries and the angular module wouldn't load at all in the tests without mocking or removing lazyLoad and httpInterceptor. I'm going to assume that isn't your issue though and the module loads. After that once I mocked out Globals it loads just fine.

So in short, be sure you are properly providing lazyLoad, httpInterceptor, and Globals to the test, either with the actual code or through mocking, and the test passes. At least for me it does.