【问题标题】:Mocking a service dependency in an Angular controller with jasmine使用 jasmine 在 Angular 控制器中模拟服务依赖项
【发布时间】:2015-03-20 03:58:12
【问题描述】:

我一直在尝试开始使用 karma 和 jasmine 进行 angular 单元测试,并且我一直在努力思考如何测试具有依赖关系的控制器。我尝试使用 jasmine spyObj 模拟间谍并将其注册到 beforeEach 挂钩中,但由于某种原因无法识别间谍。

代码如下:

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).toHaveBeenCalled(); 时,我得到“错误:预期是间谍,但得到了函数”;

如果我调用 expect($scope.data).toEqual("bar"),我得到 Expected 'foo' to equal 'bar'。 “Foo”来自实际服务,而不是间谍对象。

感谢您的帮助。

【问题讨论】:

    标签: angularjs unit-testing jasmine


    【解决方案1】:

    而不是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");
        }); 
    });
    

    【讨论】:

    • 谢谢戴文。我用上面的代码替换了我的测试,它在调用 spyOn 的行返回“无法读取未定义的属性 'returnValue'”。我将其更改为: spyOn(TestService, 'load').andReturn('bar') 并且测试现在是绿色的。 “然后。返回。”是 Jasmine 2.0 的语法吧?
    • 那么必须是 Jasmine 2.0。如果andReturn 有效,那就太好了!
    【解决方案2】:

    在您的beforeEach 中,您正在注入_TestService_,然后通过以下方式覆盖您在之前的beforeEach 中声明的那个:

    TestService = _TestService_;
    

    删除该代码,您的测试应该会成功。

    也没有必要这样做:

    $provide.value("TestService", TestService)
    

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

    【讨论】:

    • 非常感谢 Brocco 的回复。我按照您的建议删除了这两行,但测试仍然失败。它给了我:“无法读取未定义的属性'负载'”。看起来它正在尝试调用 TestService spyObj 上的负载,但它仍然没有找到 spyObj。
    • 这似乎是我的建议和 Davin 在他的回答中向您展示的间谍问题(您接受了)的结合
    猜你喜欢
    • 2021-02-12
    • 2014-11-22
    • 1970-01-01
    • 1970-01-01
    • 2013-05-04
    • 1970-01-01
    • 2011-06-15
    • 1970-01-01
    • 2016-05-03
    相关资源
    最近更新 更多