javascript - Angular : How to properly mock a Promise returned from $http

标签 javascript angularjs unit-testing jasmine angular-promise

我现在已经为此苦苦挣扎了一段时间,需要一些指导。我想对这个 Angular 服务进行单元测试……具体来说,是 promise 的失败部分。

(function () {
angular.module('testable')
    .factory('myService', ["$http", "$q", function ($http, $q) {
        return {
            createThing: function(thing) {
                return $http.post("//...", thing)
                        .then(function (response) {
                            return response.data;
                        }, function (response) {
                            return $q.reject(response.statusText);
                        });
            }
        };
    }]);
}());

我浏览过许多关于此的 SO 帖子,但每个帖子似乎都有点不同。首先,如果我的任何服务代码在设置 promise 时不正确,请阻止我。我已经通过大约 10 次不同的迭代来测试被拒绝的 promise ,但没有任何效果。这是我所拥有的:

    beforeEach(inject(function ($injector,myService) {
        sut = myService;
        $httpBackend = $injector.get('$httpBackend');
        $q = $injector.get('$q');
        $rootScope = $injector.get('$rootScope');
        dataToSend = "send me!";
        deferred = $q.defer();
    }));

    it("should get error on error", function () {
        var result,
            expected = "FAIL!!!!!";

        deferred.reject(expected);
        $httpBackend.expectPOST(testUrl,dataToSend).respond(deferred.promise);

        sut.createThing(dataToSend).then(function (returnFromPromise) {
            result = returnFromPromise;
        });

        $rootScope.$apply();
        $httpBackend.flush();

        // expect something here but result is always wrong
    });

我知道 promises 是异步运行的……我一直在拼凑一些信息,但是有人对完成这个单元测试有什么建议吗?

最佳答案

当您使用 $httpBackend 服务时,您不需要使用 promises 来模拟 HTTP 请求。事实上,respond() 方法具有以下签名:

respond: function(status, data, headers, statusText) { 
  ...
}

要模拟错误,您只需返回一个非成功状态代码 (!= 200):

it('should not create a thing', function() {
    var result;

    // Arrange
    $httpBackend.expectPOST('https://domain.com/api')
      .respond(500, null, null, 'some error');

    // Act
    myService.createThing('foo').then(angular.noop, function(data) {
      result = data;
    });

    $httpBackend.flush();

    // Assert
    expect(result).toBe('some error');
  });

下面是涵盖成功和错误案例的整个规范:

describe('Testing a factory', function() {
  var myService, $httpBackend;

  beforeEach(function() {
    module('plunker');

    inject(function(_$httpBackend_, _myService_) {
      $httpBackend = _$httpBackend_;
      myService = _myService_;
    })
  });

  afterEach(function() {
    $httpBackend.verifyNoOutstandingExpectation();
    $httpBackend.verifyNoOutstandingRequest();
  });

  it('should create a thing', function() {
    var result;

    // Arrange
    $httpBackend.expectPOST('https://domain.com/api')
  .respond(200, 'some data');

    // Act
    myService.createThing('foo').then(function(data) {
      result = data;
    });

    $httpBackend.flush();

    // Assert
    expect(result).toBe('some data');
  });

  it('should not create a thing', function() {
    var result;

    // Arrange
    $httpBackend.expectPOST('https://domain.com/api')
  .respond(500, null, null, 'some error');

    // Act
    myService.createThing('foo').then(angular.noop, function(data) {
      result = data;
    });

    $httpBackend.flush();

    // Assert
    expect(result).toBe('some error');
  });
});

Working Plunker

请注意,这里不需要调用 $rootScope.$apply(),因为不需要摘要循环来更新任何内容。

关于javascript - Angular : How to properly mock a Promise returned from $http,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30384858/

相关文章:

angularjs - $sce.trustAsHtml 过滤器未在动态数据上应用 ng-bind-html

python - 从 Django 运行 Selenium 超时错误

javascript - 如何使用正则表达式从字符串中提取所有 24 小时时间?

javascript - 错误 : Timeout - Async callback was not invoked within 5000ms (set by jasmine. DEFAULT_TIMEOUT_INTERVAL)

javascript - 将路径添加到当前 URL 位置

javascript - 如何使用对象(而不是数组)将 orderBy 和过滤器与 ng-repeat 一起使用?

javascript - mdInkRipple 波纹整个 mdVirtualRepeat - Angular Material

java - 如何构建运行测试套件的 Maven 工件? 'sbt test' 是如何工作的?

angularjs - 如何模拟单元测试的配置阶段提供程序?

javascript - 如何从 Controller 到指令模板进行通信