如何使用 Jasmine 测试从 AngularJS 控制器返回的 Promise 值?

How to Test Value Returned in Promise from AngularJS Controller with Jasmine?(如何使用 Jasmine 测试从 AngularJS 控制器返回的 Promise 值?)
本文介绍了如何使用 Jasmine 测试从 AngularJS 控制器返回的 Promise 值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

我有一个控制器,它公开了一个函数,该函数在休息调用后返回一些文本.它工作正常,但我无法用 Jasmine 测试它.测试中 Promise 处理程序中的代码永远不会执行.

I have a controller that expose a function that returns some text after a rest call. It works fine, but I'm having trouble testing it with Jasmine. The code inside the promise handler in the test never executes.

控制器:

/* global Q */
'use strict';
angular.module('myModule', ['some.service'])
    .controller('MyCtrl', ['$scope', 'SomeSvc', function ($scope, SomeSvc) {

        $scope.getTheData = function (id) {
            var deferred = Q.defer();
            var processedResult = '';
            SomeSvc.getData(id)
                .then(function (result) {
                    //process data
                    processedResult = 'some stuff';
                    deferred.resolve(processedResult);
                })
                .fail(function (err) {
                    deferred.reject(err);
                });
            return deferred.promise;
        }
    }]);

测试:

describe('some tests', function() {
    var $scope;
    var $controller;
    var $httpBackend;
    beforeEach(function() {
        module('myModule');
        inject(function(_$rootScope_, _$controller_, _$httpBackend_) {
            $scope = _$rootScope_.$new();
            $controller = _$controller_;
            $httpBackend = _$httpBackend_;
            //mock the call that the SomeSvc call from the controller will make
            $httpBackend.expect('GET', 'the/url/to/my/data');
            $httpBackend.whenGET('the/url/to/my/data')
                .respond({data:'lots of data'});
            $controller ('MyCtrl', {
                $scope: $scope
            });
        });
    });

    describe('test the returned value from the promise', function() {
        var prom = $scope.getTheData(someId);
        prom.then(function(result) {
            expect(result).toBe('something expected');  //this code never runs
        })
    });
});

推荐答案

除非调用 promise 回调,否则 then 中的任何内容都不会运行 - 这可能会像您遇到的那样出现误报风险这里.测试将通过这里,因为期望从未运行过.

Anything inside a then will not be run unless the promise callbacks are called - which is a risk for a false positive like you experienced here. The test will pass here since the expect was never run.

有很多方法可以确保您不会得到这样的误报.例子:

There are many ways to make sure you don't get a false positive like this. Examples:

Jasmine 将等待承诺在超时内得到解决.

Jasmine will wait for the promise to be resolved within the timeout.

  • 如果不及时解决,测试将失败.
  • 如果 promise 被拒绝,测试也会失败.

当心如果您忘记返回,您的测试将给出误报!

Beware If you forget the return, your test will give a false positive!

describe('test the returned value from the promise', function() {
    return $scope.getTheData(someId)
    .then(function(result) {
        expect(result).toBe('something expected');
    });
});

B) 使用 Jasmine 提供的 done 回调给测试方法

  • 如果在超时时间内没有调用 done,则测试将失败.
  • 如果使用参数调用 done,则测试将失败.
    这里的catch会将错误传递给jasmine,你会看到错误在输出中.
  • B) Use the done callback provided by Jasmine to the test method

    • If done is not called within the timeout the test will fail.
    • If done is called with arguments the test will fail.
      The catch here will pass the error to jasmine and you will see the error in the output.
    • 当心如果您忘记了捕获,您的错误将被吞没,您的测试将因一般超时错误而失败.

      Beware If you forget the catch, your error will be swallowed and your test will fail with a generic timeout error.

      describe('test the returned value from the promise', function(done) {
          $scope.getTheData(someId)
          .then(function(result) {
              expect(result).toBe('something expected');
              done();
          })
          .catch(done);
      });
      

      C) 使用间谍和手摇(同步测试)

      如果你不完美,这可能是编写测试最安全的方式.

      C) Using spies and hand cranking (synchronous testing)

      If you're not perfect this might be the safest way to write tests.

      it('test the returned value from the promise', function() {
          var
            data = { data: 'lots of data' },
            successSpy = jasmine.createSpy('success'),
            failureSpy = jasmine.createSpy('failure');
      
          $scope.getTheData(someId).then(successSpy, failureSpy);
      
          $httpBackend.expect('GET', 'the/url/to/my/data').respond(200, data);
          $httpBackend.flush();
      
          expect(successSpy).toHaveBeenCalledWith(data);
          expect(failureSpy).not.toHaveBeenCalled();
      });
      

      同步测试技巧
      您可以在需要时手动调整 httpBackend、超时和范围更改,以使控制器/服务更进一步.$httpBackend.flush(), $timeout.flush(), scope.$apply().

      这篇关于如何使用 Jasmine 测试从 AngularJS 控制器返回的 Promise 值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

      本站部分内容来源互联网,如果有图片或者内容侵犯了您的权益,请联系我们,我们会在确认后第一时间进行删除!

相关文档推荐

在开发JS过程中,会经常遇到两个小数相运算的情况,但是运算结果却与预期不同,调试一下发现计算结果竟然有那么长一串尾巴。如下图所示: 产生原因: JavaScript对小数运算会先转成二进制,运算完毕再转回十进制,过程中会有丢失,不过不是所有的小数间运算会
问题描述: 在javascript中引用js代码,然后导致反斜杠丢失,发现字符串中的所有\信息丢失。比如在js中引用input type=text onkeyup=value=value.replace(/[^\d]/g,) ,结果导致正则表达式中的\丢失。 问题原因: 该字符串含有\,javascript对字符串进行了转
Rails/Javascript: How to inject rails variables into (very) simple javascript(Rails/Javascript:如何将 rails 变量注入(非常)简单的 javascript)
CoffeeScript always returns in anonymous function(CoffeeScript 总是以匿名函数返回)
Ordinals in words javascript(javascript中的序数)
getFullYear returns year before on first day of year(getFullYear 在一年的第一天返回前一年)