【问题标题】:How do I spy on an Angular promise chain using Jasmine如何使用 Jasmine 监视 Angular 承诺链
【发布时间】:2013-11-07 02:54:11
【问题描述】:

使用 AngularJS、CoffeeScript 和 Jasmine(在 WebStorm 中编辑),我想对一系列 Promise 进行单元测试。

假设我有以下示例服务:

角度服务

class ExampleService
    stepData: []
    constructor: (@$http) ->

    attachScopeMethod: (@scope) ->
        @scope.callSteps = => @step1().then -> @step2()

    step1: ->
        @$http.get('app/step/1').then (results) =>
            @stepData[0] = results.data
            results

    step2: ->
        @$http.get('app/step/2').then (results) =>
            @stepData[2] = results.data
            results

此服务允许我将方法callSteps() 附加到范围。此方法在调用时会执行一系列对第 3 方 API 的异步 $http 调用。

为了测试每个步骤是否至少被调用,我编写了以下 Jasmine 规范。

茉莉花规格

ddescribe 'ExampleService', ->

    beforeEach ->
        module 'myApp'

    beforeEach inject ($rootScope, $injector) ->
        @scope = $rootScope.$new()
        @exampleService = $injector.get 'exampleService'
        @q = $injector.get '$q'

    describe 'process example steps', ->
        beforeEach  -> 
            @exampleService.attachScopeMethod(@scope)

        it "should attach the scope method", ->
            expect(@scope.callSteps).toBeDefined()

        describe 'when called should invoke the promise chain', ->

        it "should call step1 and step2", ->
            defer = @q.defer()
            @exampleService.step1 = jasmine.createSpy('step1').andReturn(defer.promise)

            @exampleService.step2 = jasmine.createSpy('step2')

            @scope.callSteps()
            defer.resolve()

            expect(@exampleService.step1).toHaveBeenCalled()
            expect(@exampleService.step2).toHaveBeenCalled()

本次测试结果如下:

  • 期望(@exampleService.step1).toHaveBeenCalled() - 通过
  • 期望(@exampleService.step2).toHaveBeenCalled() - 失败

您能告诉我如何让step2() 在测试中成功运行吗?

谢谢

编辑

下面的@Dashu 提供了问题的答案。诀窍是简单地调用scope.$applyscope.$digest 来触发承诺链解析。

所以这是有效的测试片段。

describe 'when called should invoke the promise chain', ->
    it "should call step1 and step2", ->
        defer = @q.defer()
        defer.resolve()

        @exampleService.step1 = jasmine.createSpy('step1').andReturn(defer.promise)
        @exampleService.step2 = jasmine.createSpy('step2')

        @scope.callSteps()
        @scope.$apply()

        expect(@exampleService.step1).toHaveBeenCalled()
        expect(@exampleService.step2).toHaveBeenCalled()

【问题讨论】:

    标签: angularjs jasmine


    【解决方案1】:

    在第二个期望之前尝试 $rootScope.$apply()

    还有关于 defer.resolve()。我不知道这是否真的解决了承诺,我认为它只是设置了解决时要返回的值。

    所以我会将它移到 $q.defer() 调用的下方,然后将承诺传递给 andReturn()

    你可以做 defer.resolve(true), defer.reject(false),所以如果你承诺会被拒绝 insinde callsteps,true 或 false 将被返回

    【讨论】:

    • apply() 做到了。我的错误是认为resolve() 方法实际上解决了承诺,但似乎存在设置要在实际解决承诺时触发的返回值(或函数)。如果您不包含样板文件resolve(),则承诺不会解决,您需要apply()resolve()
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-30
    • 2015-09-22
    • 2019-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多