简体   繁体   English

使用jasmine进行Angular2异步单元测试

[英]Angular2 async unit testing with jasmine

I'm writing an angular2 app and having trouble understanding how to write tests for async code using jasmine. 我正在编写一个angular2应用程序,并且无法理解如何使用jasmine编写异步代码的测试。 For whatever reason, I'm not seeing a lot of examples that seem terribly applicable to my situation. 无论出于何种原因,我都没有看到很多看似非常适用于我的情况的例子。

I'm currently trying to test a service (not a component) that has a async dependency on another service. 我目前正在尝试测试对另一个服务具有异步依赖性的服务(而不是组件)。 I'm not 100% sure at what point in the test it's valid to check the results of the async call. 我不是100%确定测试中的哪一点检查异步调用的结果是有效的。 Can you just call expect() inside the async handler for your service? 你能在服务的异步处理程序中调用expect()吗?

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

Here is the full test. 这是完整的测试。

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();
        });
}));

There's two aspects of dealing with async tests that you have to concern yourself about if you want to ensure your tests are actually reliable. 处理异步测试有两个方面,如果你想确保测试真正可靠,你必须关注它们。

First, you have to ensure that if a result is retrieved asynchronously, that you wait until the result is available before you try to test for it. 首先,您必须确保如果异步检索结果,则在尝试测试结果之前等待结果可用。

Hence, if the asynchronous result is a promise, for eg, you can put your expect in your then handler, just as you indicated in your question. 因此,如果异步结果是一个承诺,例如,您可以将您的expect放在then处理程序中,就像您在问题中指出的那样。

The second issue that you have to concern yourself with is forcing your test itself to wait for your expectations to execute before giving a positive (or negative) result. 您必须关注的第二个问题是强制您的测试本身在给出积极(或消极)结果之前等待您的期望执行。 If you don't deal with this, you can have cases where your expectation fails, but because your test did not wait for your asynchronous action to complete before finishing, the test reports a false positive. 如果你不处理这个问题,你可能会遇到期望失败的情况,但是因为你的测试没有等到你的异步操作在完成之前完成,所以测试会报告误报。

There are several ways of 'making your test wait'. 有几种方法可以“让你的测试等待”。

The pure jasmine way is to pass a done handler into your it function. 纯粹的茉莉花方式是将一个done处理程序传递给你的it函数。 Then jasmine will wait until that done handler is called before considering the test complete. 然后jasmine将等待,直到调用完成处理程序,然后才考虑完成测试。

eg. 例如。

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

However, angular's testing framework adds two other options to this. 但是,angular的测试框架为此添加了两个其他选项。 The first is easier to grasp if you are comfortable with async programming. 如果您对异步编程感到满意,那么第一个更容易掌握。

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

in this case, you basically wrap your test handler in an async function. 在这种情况下,您基本上将测试处理程序包装在异步函数中。 This function will force the test to wait for any async results (eg promises, observables etc) to return a result, before allowing the test to complete. 在允许测试完成之前,此函数将强制测试等待任何异步结果(例如promises,observables等)返回结果。

The second method is to use fakeAsync, which allows you to hide the async nature of your test entirely. 第二种方法是使用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 hooks into all async functions and allows you to treat them as synchronous. fakeAsync挂钩到所有异步函数,并允许您将它们视为同步。 You can use the tick() function to 'force your test to wait' for async tasks to complete before continuing. 您可以使用tick()函数“强制您的测试等待”,以便在继续之前完成异步任务。
(It's not quite doing that, but conceptually, you can think of it that way). (这不是那么做,但从概念上讲,你可以这样想)。

See the Angular docs to learn more 请参阅Angular文档以了解更多信息

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM