Jasmine测试promise.then函数

Jon*_*ans 32 javascript jasmine angularjs

我尝试用Jasmine测试我的应用程序并遇到以下问题:
我将根据then我的承诺计算一些东西.这就是我需要测试代码的地方.

这是我的控制器的代码:

  TestCtrl.$inject = ["$scope", "TestService"];
  /* ngInject */
  function TestCtrl($scope, TestService) {
    $scope.loadData = function () {
      TestService.getData().then(function (response) {
        $scope.data = response.data;
        $scope.filtered = $scope.data.filter(function(item){
          if(item.id > 1000){
            return true;
          }
          return false;
        })
      });
    }
  }
Run Code Online (Sandbox Code Playgroud)

我的Jasmine测试代码:

describe('TestService tests', function () {
  var $q;
  beforeEach(function () {
    module('pilot.fw.user');
  });
  beforeEach(inject(function (_$q_) {
    $q = _$q_;
  }));
  describe('UserController Tests', function () {

    beforeEach(inject(function (_$httpBackend_, $rootScope, $controller) {
      this.scope = $rootScope.$new();
      this.$rootscope = $rootScope;
      this.$httpBackend = _$httpBackend_;
      this.scope = $rootScope.$new();
      var TestServiceMock = {
        getData: function () {
          var deferred = $q.defer();
          var result = [{
            "id": 1720,
            "user": 1132
          },
            {
              "id": 720,
              "user": 132
            }, {
              "id": 1721,
              "user": 1132
            }];
          deferred.promise.data = result;
          deferred.resolve(result);
          return deferred.promise;
        }
      };
      this.controller = $controller('TestCtrl', {
        '$scope': this.scope,
        'TestService': TestServiceMock
      });
    }));

    it('test', function(){
      this.scope.loadData();
      expect(true).toBeTruthy();
    })
  });
});
Run Code Online (Sandbox Code Playgroud)

我不明白的奇怪之处是(使用控制台日志测试):

  • 我的承诺被创造并归还
  • 调用我的loadData函数,它将从TestService调用getData()函数
  • 虽然我将promise作为已解决的函数返回,但then函数内的所有内容都不会被执行

那我怎么能测试then函数里面的代码呢?
感谢帮助

Dus*_*les 41

茉莉花'it'方法采用一个可以调用异步测试的完成参数

it('Should be async', function(done) {
  someAsyncFunction().then(function(result) {
    expect(result).toBe(true);
    done();
  });
});
Run Code Online (Sandbox Code Playgroud)

随意尽可能深入,只要确保在一切完成后调用完成.Jasmine的默认超时是每次测试5秒,所以如果没有完成async的话,那么jasmine就会崩溃.您可以在配置中更改此设置或将其设置在终端中.

这直接来自jasmine文档,向您展示如何处理默认超时间隔

describe("long asynchronous specs", function() {
  var originalTimeout;
  beforeEach(function() {
    originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
    jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
  });

  it("takes a long time", function(done) {
    setTimeout(function() {
      done();
    }, 9000);
  });

  afterEach(function() {
    jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
  });
});
Run Code Online (Sandbox Code Playgroud)

我认为如果它在10秒内不起作用,你可能会有错误的方法.特别是如果你正在与本地服务器/ db通信.如果您正在执行重大计算,或者正在使用不那么好的互联网连接打外部api,那么这个东西应该只花这么长时间.如果一切都是本地的(或顽固/嘲笑!)那么超过5-10秒的任何东西都是明确的红旗.


Yev*_*upa 7

你最好看这个https://codecraft.tv/courses/angular/unit-testing/asynchronous/

你实际上有 3 种方法:

1)使用常规它:

it('test', (done) => {
   const spy = spyOn(func, 'bar').and.returnValue(Promise.resolve(true));
   spy.calls.mostRecent().returnValue.then(res => {
      ...your expect here...
      done();
   })
} );
Run Code Online (Sandbox Code Playgroud)

2) 在 beforeEach 中使用 async 和它:

it('test', async(() => {
    spyOn(func, 'bar').and.returnValue(Promise.resolve(true));
    fixture.whenStable().then(res => {
       ...your expect here...
    })
 } ));
Run Code Online (Sandbox Code Playgroud)

3) 如果您没有 Http 或 XHR 调用,请使用 fakeAsync:

it('test', fakeAsync(() => {
    spyOn(func, 'bar').and.returnValue(Promise.resolve(true));
    tick();
    ...your expect here...
 } ));
Run Code Online (Sandbox Code Playgroud)


mah*_*had 5

希望此解决方案有帮助。我发现测试时有用的一种方法是模拟依赖关系。我试图注释掉我所做的尽可能多的事情。

var returnMock, $scope, TestServiceMock, controller;

beforeEach(module('app'));

beforeEach(inject(function($controller) {
    returnMock = {
        then: jasmine.createSpy(),
    };
    $scope = {};
    // first assumption is You are testing TestService extensively,
    // I don't care about what getData has to do to get results
    // All I care about is it gets called when I call loadData
    TestServiceMock = {
        getData: jasmine.createSpy().and.returnValue(returnMock);
    };

    controller = $controller;
}));

it('should load data when loadData function is called and result set is 
under 1000', function() {
    controller('TestCtrl', {
        $scope,
        TestServiceMock
    });
    // another assumption is your data comes back in such a format
    // perhaps in the actual code check whether data exists and proceed
    // or do some other action
    var returnedData = {
        data: [
            {
                id: 1,
                name: 'item 1',
            },
        ]
    }
    // when I execute the function/method
    $scope.loadData();
    // I expect getData to be called
    expect(TestServiceMock.getData).toHaveBeenCalled();
    // I expect then to be called and the reason is I mocked it
    expect(returnMock.then).toHaveBeenCalledWith(jasmine.any(Function));
    returnMock.then.calls.mostRecent().args[0](returnedData);
    // expect data on scope to be equal to my mocked data
    expect($scope.data).toEqual(returnedData.data);
    // don't expect any result because 1 < 1000
    expect($scope.filtered).toEqual([]);
    expect($scope.filtered.length).toEqual(0);
});

it('should load data when loadData function is called and result set is over 1000', 
     function() {
    controller('TestCtrl', {
        $scope,
        TestServiceMock
    });
    var returnedData = {
        data: [
            {
                id: 1,
                name: 'item 1',
            },
            {
                id: 1000,
                name: 'item 1000',
            },
            {
                id: 1001,
                name: 'item 1000',
            },
            {
                id: 1002,
                name: 'item 1002',
            }
        ]
    }
    $scope.loadData();
    expect(TestServiceMock.getData).toHaveBeenCalled();
    expect(returnMock.then).toHaveBeenCalledWith(jasmine.any(Function));
    returnMock.then.calls.mostRecent().args[0](returnedData);
    expect($scope.data).toEqual(returnedData.data);
    // expect a result because some entries in the mocked data have id > 1000
    expect($scope.filtered).toEqual([
        {
            id: 1001,
            name: 'item 1000',
        },
        {
            id: 1002,
            name: 'item 1002',
        }]);
    expect($scope.filtered.length).toEqual(2);
});
Run Code Online (Sandbox Code Playgroud)

官方的Jasmine Docs广泛解释了大多数概念。希望解决方案有帮助!!!

  • 我很高兴知道你还有培根:) @KrisMolinari (2认同)