在使用jasmine进行单元测试时,如何在AngularJS中模拟服务?

时间:2013-10-09 14:01:51

标签: unit-testing angularjs jasmine

假设我的服务shop取决于两个有状态服务schedulewarehouse。如何将schedulewarehose的不同版本注入shop进行单元测试?

这是我的服务:

angular.module('myModule').service('shop', function(schedule, warehouse) {
    return {
        canSellSweets : function(numRequiredSweets){
             return schedule.isShopOpen()
                 && (warehouse.numAvailableSweets() > numRequiredSweets);
        }
    }
});

这是我的嘲笑:

var mockSchedule = {
    isShopOpen : function() {return true}
}
var mockWarehouse = {
    numAvailableSweets: function(){return 10};
}

以下是我的测试:

expect(shop.canSellSweets(5)).toBe(true);
expect(shop.canSellSweets(20)).toBe(false);

8 个答案:

答案 0 :(得分:52)

beforeEach(function () {
  module(function ($provide) {
    $provide.value('schedule', mockSchedule);
  });
});

模块是角度模拟模块提供的功能。如果传入字符串参数,则会加载具有相应名称的模块,并且所有提供程序,控制器,服务等都可用于规范。通常使用注入功能加载它们。如果传入回调函数,将使用Angular的$ injector服务调用它。然后,该服务查看传递给回调函数的参数,并尝试推断应将哪些依赖项传递给回调。

答案 1 :(得分:36)

改进Atilla的回答并直接回答KevSheedy的评论,在module('myApplicationModule')的背景下,你会做到以下几点:

beforeEach(module('myApplicationModule', function ($provide) {
  $provide.value('schedule', mockSchedule);
}));

答案 2 :(得分:7)

使用CoffeeScript我遇到了一些问题,所以我最后使用 null

beforeEach ->
  module ($provide) ->
    $provide.value 'someService',
      mockyStuff:
        value : 'AWESOME'
    null

答案 3 :(得分:6)

您可以在此处查看更多信息

https://docs.angularjs.org/guide/services#unit-testing

您想要使用$ offer服务。在你的情况下

$provide.value('schedule', mockSchedule);

答案 4 :(得分:1)

我最近发布了ngImprovedTesting模块,它可以让AngularJS中的模拟测试变得更容易。

在你的例子中,你只需要在你的Jasmine测试中替换......

beforeEach(module('myModule'));

...与......

beforeEach(ModuleBuilder.forModule('myModule').serviceWithMocks('shop').build());

有关ngImprovedTesting的更多信息,请查看其介绍性博客文章: http://blog.jdriven.com/2014/07/ng-improved-testing-mock-testing-for-angularjs-made-easy/

答案 5 :(得分:1)

将模拟器放在模块上更简单:

    beforeEach(function () {
    module('myApp');
    module({
      schedule: mockSchedule,
      warehouse: mockWarehouse
     }
    });
  });

您可以使用注射来参考这些模拟进行预测试操作:

var mockSchedule;
var mockWarehouse;

beforeEach(inject(function (_schedule_, _warehouse_) {
     mockSchedule = _schedule_;
     mockWarehouse = _warehouse_;
}));

答案 6 :(得分:1)

我希望我的回答不是没用,但你可以通过$provide.service

来模拟服务
beforeEach(() => {
    angular.mock.module(
      'yourModule',
      ($provide) => {
        $provide.service('yourService', function() {
          return something;
        });
      }
    );
  });

答案 7 :(得分:1)

当你使用茉莉花时,还有另一种方法可以使用茉莉花的间谍(https://jasmine.github.io/2.0/introduction.html#section-Spies)模仿调用。

使用这些功能可以使用函数调用进行定位,并在需要时允许对原始对象进行调用。它避免了使用$ provide和mock实现来堵塞测试文件的顶部。

在你的测试之前我会有类似的东西:

var mySchedule, myWarehouse;

beforeEach(inject(function(schedule, warehouse) {

  mySchedule = schedule;
  myWarehouse = warehouse;

  spyOn(mySchedule, 'isShopOpen').and.callFake(function() {
    return true;
  });

  spyOn(myWarehouse, 'numAvailableSweets').and.callFake(function() {
    return 10;
  });

}));

这应该与$ provide机制类似,注意你必须提供注入变量的本地实例来监视。