Angularjs 用jasmine模拟Angular控制器中的服务依赖关系

Angularjs 用jasmine模拟Angular控制器中的服务依赖关系,angularjs,unit-testing,jasmine,Angularjs,Unit Testing,Jasmine,我一直在尝试开始与karma和jasmine一起使用angular进行单元测试,我一直在绞尽脑汁想如何测试具有依赖性的控制器。我试着用一个茉莉花间谍游戏来模仿一个间谍,并把它注册到beforeach钩子里,但由于某种原因,这个间谍没有被认出 代码如下: angular.module('testModule', []) .controller('TestController', [ '$scope', 'TestService', function ($scope, Tes

我一直在尝试开始与karma和jasmine一起使用angular进行单元测试,我一直在绞尽脑汁想如何测试具有依赖性的控制器。我试着用一个茉莉花间谍游戏来模仿一个间谍,并把它注册到beforeach钩子里,但由于某种原因,这个间谍没有被认出

代码如下:

angular.module('testModule', [])
.controller('TestController', [
    '$scope',
    'TestService',
    function ($scope, TestService) {
        $scope.data = TestService.load();
    }])

.factory('TestService', function () {
    return {
        load: function(){
            return "foo";
        }
    }
});
这是测试

describe('TestController', function() {

var $controller, $scope, TestService;

beforeEach(module('testModule'), function($provide){
    TestService = jasmine.createSpyObj("TestService", ["load"]);
    TestService.load.andReturn("bar");
    $provide.value("TestService", TestService)
});

beforeEach(inject(function(_$controller_, $rootScope, _TestService_) {
    $scope = $rootScope.$new();
    TestService = _TestService_;
    $controller = _$controller_('TestController', {
        $scope: $scope,
        TestService: TestService
    });
}));

it('should set $scope.data to bar when TestService.load is called', function() {
    expect(TestService.load).toHaveBeenCalled();
    expect($scope.data).toEqual("bar");
}); });
测试中的两个断言都失败

当我调用expect(TestService.load).tohavebeencall()时,我得到了“Error:Expected是间谍,但得到了函数”

如果我调用expect($scope.data).toEqual(“bar”),我会得到预期的'foo'等于'bar'。“Foo”来自实际的服务,而不是间谍对象


谢谢你的帮助

在您的
beforeach
中,您正在注入
\u TestService\u
,然后通过以下方式覆盖您在前面的
beforeach
中声明的内容:

TestService = _TestService_;
删除该代码,测试就会成功

此外,无需这样做:

$provide.value("TestService", TestService)

基本上,当您手动注入不必要的东西时,您尝试使用Angular的依赖注入。

而不是
jasmine.createSpyObj
,使用
$injector
提供的现有服务,然后模拟单个方法会更容易。您可以使用
spyOn
来实现这一点:

describe('TestController', function() {

var $controller, $scope, TestService;

beforeEach(module('testModule'));

beforeEach(inject(function(_$controller_, $rootScope, _TestService_) {
    $scope = $rootScope.$new();
    TestService = _TestService_;
    spyOn(TestService, 'load').and.returnValue('bar');
    $controller = _$controller_('TestController', {
        $scope: $scope,
        TestService: TestService
    });
}));

it('should set $scope.data to bar when TestService.load is called',       function() {
        expect(TestService.load).toHaveBeenCalled();
        expect($scope.data).toEqual("bar");
    }); 
});

非常感谢布罗科的回复。我按照你的建议删除了两行,但测试仍然失败。它告诉我:“无法读取未定义的属性‘load’”。看起来它试图调用TestService spyObj上的load,但仍然找不到spyObj。这似乎是我的建议和Davin在回答(你接受了)中向你展示的间谍问题的结合。谢谢Davin。我用上面的代码替换了我的测试,它在调用spyOn的行中返回'cannotreadproperty'returnValue'of undefined'。我把它改为:spyOn(TestService,'load')。andReturn('bar'),现在测试是绿色的。“and.return.”是Jasmine 2.0语法,对吗?那么一定是Jasmine 2.0。如果
andReturn
有效,那就太好了!