65

假设我有一个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);
4

8 回答 8

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

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

于 2013-10-09T14:38:21.437 回答
37

改进 Atilla 的回答并直接回答 KevSheedy 的评论,在您的上下文中,module('myApplicationModule')您将执行以下操作:

beforeEach(module('myApplicationModule', function ($provide) {
  $provide.value('schedule', mockSchedule);
}));
于 2014-02-27T13:04:10.623 回答
7

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

beforeEach ->
  module ($provide) ->
    $provide.value 'someService',
      mockyStuff:
        value : 'AWESOME'
    null
于 2014-02-03T17:15:53.883 回答
6

你可以在这里查看更多信息

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

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

$provide.value('schedule', mockSchedule);
于 2013-10-09T14:37:13.720 回答
2

当您使用 jasmine 时,还有另一种方法可以使用 jasmine 的间谍(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 机制类似的方式工作,注意您必须提供注入变量的本地实例以进行监视。

于 2017-03-23T14:42:32.923 回答
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/

于 2014-07-29T00:22:03.960 回答
1

像这样将模拟放在模块上更简单:

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

您可以使用注入来获取对这些模拟的参考以进行预测试操作:

var mockSchedule;
var mockWarehouse;

beforeEach(inject(function (_schedule_, _warehouse_) {
     mockSchedule = _schedule_;
     mockWarehouse = _warehouse_;
}));
于 2015-06-28T18:59:35.783 回答
1

我希望我的回答不是那么无用,但是您可以通过以下方式模拟服务$provide.service

beforeEach(() => {
    angular.mock.module(
      'yourModule',
      ($provide) => {
        $provide.service('yourService', function() {
          return something;
        });
      }
    );
  });
于 2016-05-03T11:30:59.003 回答