使用jasmine测试异步功能

时间:2017-08-01 18:00:39

标签: javascript angularjs unit-testing asynchronous jasmine

我们在使用Jasmine测试异步代码时遇到了意外行为。据我们所知,当您使用done函数时,在执行完成之前不会调用期望值。但是,这没有发生,因为第二个期望失败,因此$ctrl.todos任务从未发生过

不工作测试

it('initializes the data when $onIinit', (done) => {
  const expected = 'some result';
  const response = Promise.resolve(expected);

  spyOn(myService, 'getAll').and.returnValue(response);

  // This method calls myService.getAll
  $ctrl.$onInit();

  expect(myService.getAll).toHaveBeenCalled();
  expect($ctrl.todos).toEqual(false);

  response.then(done);
});

输出:预期未定义为等于

另一方面,这是有效的:

it('initializes the data when $onIinit', (done) => {
    const expected = 'some result';
    const response = Promise.resolve(expected);

    spyOn(myService, 'getAll').and.returnValue(response);

    // This method calls myService.getAll
    $ctrl.$onInit();

    expect(myService.getAll).toHaveBeenCalled();
    response
      .then(() => expect($ctrl.todos).toBe(expected))
      .then(done);
  });

输出:测试通过

控制器方法:

$ctrl.$onInit = () => {
  myService.getAll().then((data) => {
    $ctrl.todos = data;
  });
};

3 个答案:

答案 0 :(得分:2)

我找到了解决方案。我真的不需要另一个then。具有done的规范在完成调用之前将无法完成。此外,它应始终放在期望之后。

工作代码:

it('initializes the data when $onIinit', (done) => {
  const expected = 'some result';
  const response = Promise.resolve(expected);
  spyOn(myService, 'getAll').and.returnValue(response);
  $ctrl.$onInit();

  expect(myService.getAll).toHaveBeenCalled();
  response
    .then(() => {
      expect($ctrl.todos).toBe(expected);
      done();
  });
});

答案 1 :(得分:0)

您的aproach似乎是正确的,并且可能在done内调用afterEach将使其正常工作。

afterEach(function(done) {
  done();
}, 1000);

但是,我建议使用$httpBackend,这是适用于使用$http service的单元测试应用程序的虚假HTTP后端实现。我们正在使用angularjs,对吧?那么,为什么不利用?

使用$httpBackend我们可以发出请求,然后使用模拟数据进行响应,而无需将请求真正发送到真实服务器。这是一个示例性的例子

it('initializes the data when $onIinit', () => {
    const mockData = { data: { expected: 'some result' } };

    spyOn(myService, 'getAll').and.callThrough();

    $httpBackend.expect('POST', '/my-service/url').respond(200, mockData);

    // This method calls myService.getAll
    $ctrl.$onInit();

    //flush pending request
    $httpBackend.flush();

    expect(myService.getAll).toHaveBeenCalled();
    expect($ctrl.todos).toBeDefined();
});

有些解释$httpBackend.expect('POST', '/my-service/url'),请注意'POST'需要与method中您的服务使用的myService.getAll相匹配,'/my-service/url'url 1}}您的服务也在myService.getAll中使用。

需要致电$httpBackend.flush();,它会释放所有待处理的请求。

您需要在测试中注入$httpBackend,这将是一种简单的方法

describe('$httpBackend service in module ngMock', () => {
    let $httpBackend;

    beforeEach(inject(['$httpBackend', (_$httpBackend) => {
        $httpBackend = _$httpBackend;
    }]));

    it('$httpBackend is defined', () => {
        // here we can use $httpBackend
        expect($httpBackend).toBeDefined();
    });
});

另请注意,$httpBackendngMock模块的一部分。

有关测试angularjs代码here

的更多信息

希望有所帮助

答案 2 :(得分:-1)

Promise来自Angular世界之外 - 您必须等待下一个事件队列中可用的结果 - 脏(几乎是脏的)黑客是使用setTimeout

angular.module('test', [])
  .controller('underTest', function($scope, myService) {
    $scope.$onInit = function() {
      myService.getAll().then(function(data) {
        $scope.todos = data
      })
    }
  })

describe('Controller: somethingChanged', function() {
  var scope, myService

  beforeEach(function() {
    module('test')
  })

  beforeEach(function() {
    module(function($provide) {
      $provide.value('myService', {
        getAll: function() {}
      })
    })
  })

  beforeEach(inject(function($controller, _$rootScope_, _myService_) {
    myService = _myService_
    scope = _$rootScope_.$new()
    $controller('underTest', {
      $scope: scope
    })
  }))

  it('initializes the data when $onIinit', function(done) {
    const expected = 'some result'
    const response = Promise.resolve(expected)

    spyOn(myService, 'getAll').and.returnValue(response)

    scope.$onInit()

    expect(myService.getAll).toHaveBeenCalled();

    setTimeout(function() {
      expect(scope.todos).toEqual(expected)
      done()
    })
  });
});
<script src="https://cdn.jsdelivr.net/jasmine/2.6.1/jasmine.js"></script>
<script src="https://cdn.jsdelivr.net/jasmine/2.6.1/jasmine-html.js"></script>
<script src="https://cdn.jsdelivr.net/jasmine/2.6.1/boot.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/jasmine/2.6.1/jasmine.css" />

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-mocks.js"></script>