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

Jasmine controller and mock service not being injected into the unit tests

这是我的 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)

报错说无法读取defined的属性 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 模块)。

如我的评论所述,您可以直接模拟服务并避免使用间谍。此外,您可以告诉 $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();
});