Jasmine控制器和模拟服务没有注入单元测试

时间:2016-01-09 01:13:10

标签: angularjs jasmine karma-jasmine

这是我的test_sp.js文件:

describe('Controller: MainCtrl', function() {
    var ctrl, mockBaseService;

    beforeEach(function() {

        mockBaseService = {
            cerrorMessages: 'whatever',
            sp: "[{'spName': 'Test'}]",
            // Calls back if errors.
            add: jasmine.createSpyObj('BaseService.add', ['sp']),
            logout: jasmine.createSpy('BaseService.logout'),
            // Calls back if errors.
            fetch: jasmine.createSpyObj('BaseService.fetch', ['selfsp'])
        };

        mockBaseService.add.sp.and.callFake(function(something, cb) {
            cb(); // execute the callback immediately
        });

        mockBaseService.fetch.selfsp.and.callFake(function(something, cb) {
            cb(); // execute the callback immediately
        });

        module('SpPageApp');

        // Let ctrl = MainCtrl and override BaseService in MainCtrl to be
        // the mockBaseService above.
        inject(function($controller) {
            ctrl = $controller('MainCtrl', {
                BaseService: mockBaseService
            });
        });
    });

    it('should have an add function', function() {
        expect(ctrl.add).toBeDefined();
    });
});

这是我的业力配置文件的file数组:

files: [
  '../angular.js',
  'node_modules/angular-mocks/angular-mocks.js',
  '../w.js',
  '../sp.js',
  '../s.js',
  '../base.js',
  'tests/test_sp.js',
],

最后,这是我的sp.js,其中包含SpPageApp模块:

angular.module("SpPageApp", ["BaseApp"])
    .controller("MainCtrl", ["$http", "$window", "BaseService", function($http, $window, BaseService) {

        var self = this;

        BaseService.fetch.selfsp(function() {
            self.sp = BaseService.sp;
            self.cerrorMessages = BaseService.cerrorMessages;
        });

        self.add = function() {
            BaseService.add.sp(self.sp, function() {
                self.cerrorMessages = BaseService.cerrorMessages;
            });
        };

        self.logoutUser = function() {
            BaseService.logout();
        };

    }]);

我做karma start来测试代码,我收到一个错误说:

Chromium 47.0.2526 (Ubuntu 0.0.0) Controller: MainsCtrl should have an add function FAILED
    TypeError: Cannot read property 'and' of undefined
        at Object.<anonymous> (/home/a/Documents/CMS/CMSApp/static/js/karma/tests/test_sp.js:20:45)
    TypeError: Cannot read property 'add' of undefined
        at Object.<anonymous> (/home/a/Documents/CMS/CMSApp/static/js/karma/tests/test_sp.js:36:20)
Chromium 47.0.2526 (Ubuntu 0.0.0): Executed 1 of 1 (1 FAILED) (0 secs / 0.006 secChromium 47.0.2526 (Ubuntu 0.0.0): Executed 1 of 1 (1 FAILED) ERROR (0.034 secs / 0.006 secs)

错误说它无法读取已定义的属性add,并指向此行:

expect(ctrl.add).toBeDefined();

并且它无法读取未定义的属性and,并指向此行:

mockBaseService.fetch.selfsp.and.callFake(function(something, cb) {

为什么Jasmine说ctrlmockBaseService.fetch.selfsp在代码中定义时未定义?

编辑:对于它的价值,w.jssp.jss.js(正在加载的业力)都有名为MainCtrl的控制器,但每个控制器都在其自己的文件中和AngularJS模块(在test_sp.js中,我只加载SpPageApp模块。)

1 个答案:

答案 0 :(得分:2)

正如我的评论中所提到的,您可以直接模拟服务并避免使用间谍。此外,您可以告诉$ injector使用您的模拟服务而不是真正的实现,允许您在解析服务时直接注入模拟,这将取代您的正常实现。

假设您的BaseService存在于SpPageApp模块中:

mockBaseService = {
    cerrorMessages: 'whatever',
    sp: "[{'spName': 'Test'}]",
    add: function (something, cb) { cb() },
    ...
};

module('BaseApp', function($provide) {
    $provide.value('BaseService', mockBaseService);
});

module('SpPageApp');

inject(function($controller) {
    ctrl = $controller('MainCtrl', {
    });
});

要进行测试,如评论中所述,您仍然希望使用间谍来确保成功调用它。

it('should have an add function', function() {
    spyOn(mockBaseService, 'add');        
    ctrl.add();
    expect(mockBaseService.add).toHaveBeenCalled();
});