【问题标题】:mock angularjs service for unit testing using jasmine使用 jasmine 进行单元测试的模拟 angularjs 服务
【发布时间】:2014-01-22 07:42:13
【问题描述】:

我有一个 Angular 应用程序,我想使用 jasmine 为其创建单元测试用例。
在我的 AngularJS 应用程序中,我有一个服务:

var canceler;
var myServices = angular.module('myServices', ['ngResource'])

myServices.factory('getData', ['$http', '$q', function($http, $q){
    var canceler;
    return {
        setData: function(url, callback, error) {
                    canceler = $q.defer();
                    $http.post(url, {}, {timeout:canceler.promise}).success(callback).error(error);
        },
        abort: function(){ canceler.resolve();}
    }
}]);

控制器正在使用此服务。

现在我如何为我在 controllerSpecs.js 中使用的注入器提供这个 "getData" 服务的模拟(用于使用 jasmine 进行单元测试)。

作为参考,controllerSpecs.js的代码定义在Getting error while using Jasmine with AngularJS中。

【问题讨论】:

    标签: angularjs jasmine


    【解决方案1】:

    您可以使用 AngularJS 的 $provide 服务。 This page 演示了如何使用 Jasmine's spies 模拟服务的功能。基本上,在您的 Jasmine 测试中,您可以包括:

    var getDataMock;
    
    beforeEach(function() {
      getDataMock = {
        setData: jasmine.createSpy(), 
        abort: jasmine.createSpy()
      };
    
      module(function($provide) {
        $provide.value('getData', getDataMock);
      });
    });
    

    这告诉 AngularJS 不是使用真正的 getData 服务,而是使用 mock 代替它。在此示例中,使用 Jasmine spy 进行模拟可以让您轻松创建关于控制器如何以及何时调用 getData 服务的预期。您也可以将getDataMock 设置为任何其他对象,尽管支持与真正的getData 服务相同的API 是有意义的。

    对于加分,您可以在单独的文件中指定 getDataMock 对象,以便在被测试的事物使用 getData 的任意数量的单元测试中轻松使用模拟。然而,这需要对您使用的任何 Jasmine 跑步者进行一些配置。

    这一切都假设您希望对控制器进行单元测试。如果你想对 getData 服务本身进行单元测试,AngularJS 提供了一个很好的 mocking utility 专门用于 http 请求。

    【讨论】:

    • 我使用了您所写的 getDataMock 并收到以下错误 - TypeError: Cannot read property 'running' of undefined at isSpecRunning in angular-mock.js
    • 我使用了您所写的 getDataMock 并收到以下错误 - TypeError: Cannot read property 'running' of undefined at isSpecRunning in angular-mock.js
    • @r.bhardwaj - 你能在 JSFiddle 中发布你的整个例子吗?
    • 我真的需要了解如何实现您的“奖励点”。如何在“$provide”中指定模拟服务?
    • 答案中的链接已失效
    【解决方案2】:

    试试这样的

    //creation mock service
    var mockGetData = {
      data: [],
      setData: function(url, callback, error){
        //emulate real work, any logic can be here
        data.push('called');
        callback(data);
      }
    }
    

    以及模拟服务的使用

    it('test description', inject(function ($rootScope, $controller){
      var scope = $rootScope.$new();
      var ctrl = $controller('TodoController', { $scope: scope, getData: mockGetData });
      //some test here....
    }))
    

    【讨论】:

    • 我无法理解,当我们将空白数据和一个函数放在 mockgetdata 的名称中什么都不做时,当我从 jasmin 调用相同的函数来测试它的功能时会发生什么?
    • @r.bhardwaj,您可以在setData函数中模拟真实GetData的工作,data属性不是必需的,您可以在测试期间保存一些数据。我已经更新了答案,但我不知道你的服务逻辑,所以你可以在那里使用任何逻辑。
    • 明白了,但还有一件事要问 - 如果不是创建模拟,我使用 $injector.get('getData') 获得“getData”服务,那有什么害处?
    • 无害。但是单元测试意味着您测试每个块彼此独立。因此,如果您的测试失败并且您使用模拟服务,您可以确定问题不在服务中。否则你需要更多的时间来找出错误的原因。
    猜你喜欢
    • 1970-01-01
    • 2013-10-16
    • 1970-01-01
    • 2015-12-18
    • 2013-06-29
    • 2016-10-22
    • 1970-01-01
    • 2013-04-01
    相关资源
    最近更新 更多