使用 jasmin 使用带有 async/await 的 $httpBackend 测试角度服务

Posted

技术标签:

【中文标题】使用 jasmin 使用带有 async/await 的 $httpBackend 测试角度服务【英文标题】:Testing angular service with $httpBackend with async/await using jasmin 【发布时间】:2018-01-18 06:01:03 【问题描述】:

我之前已经成功测试了一个使用 ES7 async/await 语法和 jasmine 的角度控制器 -

async updateGridAsync() 
        const paging = angular.copy(this.gridData.getServerCallObj());            
        
        try 
            const model = await this.service.getAsync(paging);
            this._$rootScope.$apply();
         catch (e)this._notification.error(this._$rootScope.lang.notifications.unexpectedError);
        
    

it('updateGridAsync() should update the gridData when succeed', async (done) => 
    expect(ctrl.gridData.totalItems).toEqual(2);
    expect(ctrl.gridData.items.length).toEqual(2);
    spyOn(service, 'getAsync').and.callFake(() => 
        return Promise.resolve(responseStub);
    );
    await ctrl.updateGridAsync();
    expect(service.getAsync).toHaveBeenCalled();
    expect(ctrl.gridData.totalItems).toEqual(1);
    expect(ctrl.gridData.items.length).toEqual(1);
    done();
);

上面的代码完美运行。但是,在尝试测试调用 $http.post 的模拟服务代码时,我遇到了一个问题。这是我在服务中运行的代码:

async getAsync(pagingData, spinner, gridId, payeeId)            
        const response = await $http.post(url, params);
        const model = this.modelFactory(response.data);
        return model ;
    

以及updateGridService中的await之后无法执行一步的测试方法:

it('getAsync should return correct model', async (done) =>                 
    $httpBackend.whenPOST(theUrl).respond(200, responseStub);

    const model = await service.getAsync();

    expect(model.list.length).toEqual(2);        
    $httpBackend.flush();
    done();
);

有几点需要指出——

在使用异步等待之前,此测试已通过。现在,我没有通过服务中的等待。 该功能在不在测试环境中时有效。 我正在使用 jasmine 2.4.1 和 angularJS 1.6

【问题讨论】:

你有没有找到任何通过异步等待通过测试的解决方案? 【参考方案1】:

我不认为你可以一起使用它们 - await 实际上是在等待后端承诺解决并且由刷新触发,但在发出任何请求之前触发它也没有好处。

我的意思是,如果您想以一种直接的方式使用它,我个人将它与一个助手一起使用,该助手会为刷新操作创建超时,然后等待请求。

export async function withHttp(
    callbackHttp: (http: HttpTestingController) => void,
    callbackTest: () => Promise<void>
): Promise<void> 
    const http = TestBed.get(HttpTestingController);
    setTimeout(() => callbackHttp(http));
    await callbackTest();


也不要将异步测试方法与 done 一起使用(并且不要在测试的最后一行调用 done 时使用它,那时就不需要了)。

【讨论】:

【参考方案2】:

刚刚遇到同样的问题,我认为没有解决方案。也许升级到 Angular 7 会有所帮助,希望问题在那里得到解决。但这不是一个快速的解决方案。

等待执行 HTTP 调用的异步方法会导致死锁,因为在调用 $httpBackend.flush() 之前,HTTP 调用不会返回。

不等待异步方法也无济于事。那么$httpBackend.flush() 之后的断言可能会失败,因为框架在继续断言之前没有等待足够长的时间。

我真的很想知道这个“魔法”是如何实现的。似乎当异步方法返回voidIPromise&lt;void&gt; 时,它可以工作。但是返回Promise&lt;void&gt;(或使用async)不起作用。

【讨论】:

以上是关于使用 jasmin 使用带有 async/await 的 $httpBackend 测试角度服务的主要内容,如果未能解决你的问题,请参考以下文章

jasmine matcher函数不在angularjs / karma单元测试中加载

带有属性的函数的 TypeScript 接口

Jasmine spyOn 函数和返回对象

在 Azure DevOps 测试结果中显示 Jasmine 屏幕截图

Spec没有期待——Jasmine测试回调函数

Angular 1.x Browserify Jasmine 如何设置代码覆盖测试?