AngularJS& Jasmine - spyOn异步服务问题

时间:2014-10-14 15:51:50

标签: angularjs unit-testing asynchronous jasmine

我正在尝试对通过异步服务获取一些已翻译字符串的控制器进行单元测试,但我在Jasmine vs Promises中遗漏了一些内容......

让我们从错误开始,即:

TypeError: 'undefined' is not an object (evaluating 'i18n.get('navigation').then')

测试用例

  beforeEach(inject(function ($rootScope) {
    scope = $rootScope.$new()
  }))

  it('should invoke the i18n service for translations', inject(function ($controller, i18n) {

    spyOn(i18n, 'get')
    var HeaderCtrl = $controller('HeaderCtrl', {
      $scope: scope,
      i18n: i18n
    })

    expect(i18n.get).toHaveBeenCalledWith('navigation')

  }))

控制器

  .controller('HeaderCtrl', function ($scope, i18n) {

    // removing the '.then' part makes the test pass,
    // which makes me almost sure that my missing is in the promise mamnagement
    i18n.get('navigation').then(
      function (data) {
        $scope.strings = data
      },
      function (err) {
        console.log(err)
      })

异步服务

      get: function (key) {
        var deferred = $q.defer()

        $http.get('locale/en.json')
          .success(function (data) {
            deferred.resolve(data[key])
          })
          .error(function (err, status) {
            deferred.reject(err, status)
          })

        return deferred.promise
      }

我也尝试添加一些$http模拟,但无济于事

使用$ http模拟测试

  beforeEach(inject(function ($rootScope, $httpBackend) {
    scope = $rootScope.$new()

    $httpBackend.whenGET('locale/en.json')
      .respond(enStrings)
  }))

  it('should invoke the i18n service for translations', inject(function ($controller, i18n) {

    spyOn(i18n, 'get')
    var HeaderCtrl = $controller('HeaderCtrl', {
      $scope: scope,
      i18n: i18n
    })
    $httpBackend.flush()

    expect(i18n.get).toHaveBeenCalledWith('navigation')

  }))

1 个答案:

答案 0 :(得分:2)

我终于绕过这个 希望这个答案对其他人有帮助。

我所需要的只是一个嘲笑的承诺,而不是真正的回归:

  // Initialize the controller and a mock scope
  beforeEach(inject(function ($rootScope) {
    scope = $rootScope.$new()
  }))

  it('should invoke the i18n service for translations', inject(function ($controller, i18n) {

    var fakePromise = function () {
      return {
        then: function (ok, err) {},
        success: function (ok) {},
        error: function (err) {}
      }
    }

    // when i18n.get('navigation') gets called, return my fake promise
    spyOn(i18n, 'get').andCallFake(fakePromise)

    var HeaderCtrl = $controller('HeaderCtrl', {
      $scope: scope,
      i18n: i18n
    })

    expect(i18n.get).toHaveBeenCalledWith('navigation')

  }))