【问题标题】:Angular2 async unit testing with jasmine使用 jasmine 进行 Angular2 异步单元测试
【发布时间】:2017-03-20 18:44:41
【问题描述】:

我正在编写一个 angular2 应用程序,但无法理解如何使用 jasmine 为异步代码编写测试。无论出于何种原因,我没有看到很多似乎非常适用于我的情况的示例。

我目前正在尝试测试对另一个服务具有异步依赖关系的服务(不是组件)。我不能 100% 确定在测试中的什么时候检查异步调用的结果是有效的。您可以在异步处理程序中为您的服务调用 expect() 吗?

service.foo()
    .then((data) => {
        //do I check the results in here?
        expect(data).toEqual({ a: 1, b: 2 });
        expect(mockDep.get).toHaveBeenCalled();
    });

这是完整的测试。

import { TestBed, inject } from '@angular/core/testing';
import { MyService } from './my.service.ts';
import { MyDependency } from './dependency.service.ts';

class MockDependency {
    doSomething(): Promise<any> {
        throw Error('not implemented');
    };
}

describe('some tests', () => {
    beforeEach(() => {
        TestBed.configureTestingModule({
            providers: [
                MyService,
                {
                    provide: MyDependency, useClass: MockDependency
                }
            ]
        });
    });
});

it('should do something', inject([MyService, MyDependency], (service: MyService, mockDep: MyDependency) => {
    spyOn(mockDep, 'doSomething').and.callFake(function () {
        return Promise.resolve({ a: 1, b: 2 });
    });

    service.foo()
        .then((data) => {
            //do I check the results in here?
            expect(data).toEqual({ a: 1, b: 2 });
            expect(mockDep.get).toHaveBeenCalled();
        });
}));

【问题讨论】:

  • 是的,通常你只需将expect 放在then 中。您需要在异步测试中将 injectasyncfakeAsync 包装起来。

标签: unit-testing angular asynchronous jasmine


【解决方案1】:

如果您想确保您的测试确实可靠,您必须关注处理异步测试的两个方面。

首先,您必须确保如果异步检索结果,则在尝试测试之前等到结果可用。

因此,如果异步结果是一个承诺,例如,您可以将您的 expect 放入您的 then 处理程序中,就像您在问题中指出的那样。

您必须关注的第二个问题是强制您的测试本身等待您的期望执行,然后再给出正面(或负面)结果。如果您不处理此问题,您可能会遇到预期失败的情况,但由于您的测试没有等待异步操作完成后才完成,因此测试会报告误报。

有几种方法可以“让您的测试等待”。

纯粹的 jasmine 方法是将 done 处理程序传递给您的 it 函数。然后 jasmine 会等到 done 处理程序被调用后才考虑测试完成。

例如。

it('tests an async action', (done) => {
   asyncAction().then(result => {
     expect(result).toEqual(true);
     done();
   });
});

然而,Angular 的测试框架为此添加了另外两个选项。如果您熟悉异步编程,第一个更容易掌握。

it('tests an async action', async(() => {
   asyncAction().then(result => {
     expect(result).toEqual(true);
   });
}));

在这种情况下,您基本上将您的测试处理程序包装在一个异步函数中。此函数将强制测试等待任何异步结果(例如,promise、observables 等)返回结果,然后才允许测试完成。

第二种方法是使用 fakeAsync,它允许您完全隐藏测试的异步性质。

it('tests an async action', fakeAsync(() => {
   let myResult;
   asyncAction().then(result => {
     myResult = result;
   });

   tick();   <--- force all async actions to complete
   expect(myResult).toEqual(true);
}));

fakeAsync 挂钩到所有异步函数,并允许您将它们视为同步的。您可以使用 tick() 函数“强制您的测试等待”异步任务完成后再继续。
(它并没有完全做到这一点,但从概念上讲,你可以这样想)。

See the Angular docs to learn more

【讨论】:

  • 好答案。一个问题:在使用 async() 的示例中,您仍在调用 jasmine 的 done() 函数。有必要吗?
  • @d512,你是对的——如果使用异步,就不需要 done() 调用。我更新了答案中的代码以反映这一点
猜你喜欢
  • 2013-06-28
  • 1970-01-01
  • 2017-06-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-20
  • 2016-10-30
  • 2017-05-10
  • 2016-08-14
相关资源
最近更新 更多