我如何用sinon模拟angular的$ http?

时间:2016-01-08 02:52:10

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

我试图在摩卡测试中使用sinon对angular的$ http进行简单的模拟。

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

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

searchResource.typeAhead返回一个promise,但我尝试将检查代码放在.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();
    });
  });
});

2 个答案:

答案 0 :(得分:4)

问题出在Sinon嘲笑之外。

如果直接使用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间谍而不是原始的$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;

请注意,这会使Sinon监视$http函数,而不是its methods

如果问题是关于如何与Sinon接近Angular模拟,那么它就像那样容易。否则,这可能表示XY问题,而另一个答案直接解决它($httpBackend,并且$http包含它的方式恰好使得模拟XMLHttpRequest请求的负担不存在。)

答案 1 :(得分:3)

Angular是在考虑测试的基础上构建的。之前的评论并不是说你不能使用sinon来模拟$ http,它只是不常见的做法,它肯定不会像使用$ httpBackend一样容易。

我个人只会使用sinon来模拟任何不属于Angular的依赖项。使用$ httpBackend:

提供模拟响应非常容易
hasPrevious()

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