【问题标题】:How do I mock angular's $http with sinon?如何用 sinon 模拟 Angular 的 $http?
【发布时间】:2016-04-12 15:29:01
【问题描述】:

我正在尝试在 Mocha 测试中使用 sinon 对 angular 的 $http 进行简单的模拟。

但是无论我怎么尝试,我的间谍都没有任何结果。

searchResource.typeAhead 是我正在测试的函数。它根据它的参数调用 $http,我想确保请求是正确的。

searchResource.typeAhead 返回一个承诺,但我尝试将检查代码放入 .then() 中,但它永远不会执行。

suite('Search Resource', function() {

  var injector = angular.injector(['cannonball-client-search', 'cannonball-client-core']);
  var searchResource = injector.get('SearchResource');

  suite('#typeAhead()', function () {
    setup(function () {
      this.server = sinon.fakeServer.create();
      this.server.respondWith('GET',
        config.endpoints.search.typeAhead,
        [200, {'Content-Type': 'application/json'}, '[{ "id": 12, "comment": "Hey there" }]']);
      this.spyhttp = sinon.spy(injector.get('$http'));
    });
    teardown(function () {
      this.server.restore();
    });
    test('positive', function (done) {
      searchResource.typeAhead(
        'expl',
        [{entityType: 'itementity'}],
        [{createdBy: 'Eric'}, {createdBy: 'Tal'}],
        10
      );
      this.server.respond();
      expect(this.spyhttp.calledWith({
        method: 'get',
        url: config.endpoints.search.typeAhead +
        '?query=expl&filter=entityType:itementity&orfilter=createdBy:Eric&orfilter=createdBy:Tal&limit=10'
      })).to.be.true();
      done();
    });
  });
});

【问题讨论】:

  • 简短的回答是你不使用 sinon 来模拟$http。请参阅@Phil 的资源以了解您需要使用的内容。它基于 ng 框架调用,因此您会发现使用它进行测试要容易得多。
  • 好的,所以我“不” - 你能解释为什么我不应该这样做吗?诗乃应该可以嘲讽什么吧?为什么不用 $http?

标签: angularjs unit-testing mocha.js sinon sinon-chai


【解决方案1】:

问题不在于诗乃的嘲笑。

如果直接使用angular.injector 而不是建议的angular.mock.module and angular.mock.inject helpers,则需要他自己掌握它以及他对Angular 注入器的了解。

明显的缺点是注入器不会在每个规范之后自动拆除(而在使用 angular.mock.module 时会自动拆除),因此所有嵌套规范都在同一个 Angular 注入器实例上运行。

此时

  var searchResource = injector.get('SearchResource');

SearchResource 服务实例已经被注入了 unmocked $http,这就是故事的结局。即使不会,Angular 也不可能知道应该使用this.spyhttp spy 来代替原来的$http 服务。实例化后可以窥探其方法

sinon.spy($http, 'get');

但不是$http 函数本身。

angular.injector进行测试的策略可能是

var $httpSpy;
var injector = angular.injector([
  'cannonball-client-search',
  'cannonball-client-core',
  function ($provide) {
    $provide.decorator('$http', function ($delegate) {
      return ($httpSpy = sinon.spy($delegate));
    });
  }
]);

// injector.get('$http') === $httpSpy;

请注意,这将使诗浓监视 $http 函数,而不是 its methods

如果问题是关于如何使用 Sinon 处理 Angular 模拟,那么就这么简单。否则,这可能表明存在 XY 问题,而另一个答案直接解决了它($httpBackend$http 包含它的方式正是为了消除模拟 XMLHttpRequest 请求的负担)。

【讨论】:

    【解决方案2】:

    Angular 在构建时考虑到了测试。前面的 cmets 并不是说​​不能用 sinon 来模拟 $http,这只是不常见的做法,而且肯定不会像 $httpBackend 那样容易。

    我个人只会使用 sinon 来模拟任何不属于 Angular 的依赖项。使用 $httpBackend 提供模拟响应很容易:

    $httpBackend.when('GET', '/url').respond({
        mock: 'response'
    });
    

    现在对“/url”的任何请求都使用模拟响应对象。我确定 $httpBackend 还内置了一些其他复杂的魔法来处理拦截器之类的其他事情?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-02-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-23
      • 1970-01-01
      • 2017-10-08
      • 2019-03-24
      相关资源
      最近更新 更多