简体   繁体   English

Angular - 如何使用异步服务调用对测试组件进行单元化

[英]Angular - How to unit test component with asynchronous service call

I have the following component which retrieves data from an Angular service: 我有以下组件从Angular服务检索数据:

export class MyComponent {
    constructor() {
        myService.get().then(() => {
            console.log('hello from constructor');
        });
    }
}

And then my unit test: 然后我的单元测试:

///////////

it('does something', () => {
    console.log('hello from unit test');
});

///////////

Unfortunately this results in the following log: 不幸的是,这导致以下日志:

> hello from unit test
> hello from constructor

How can I make sure that the constructor finishes before running the unit test? 如何在运行单元测试之前确保构造函数完成?

Do not use the constructor to load data, implement the OnInit interface instead. 不要使用构造函数来加载数据,而是实现OnInit接口。

import { OnInit } from '@angular/core';
export class MyComponent implements OnInit {

    constructor(private myService: MyService) {}

    ngOnInit() {
        myService.get().then(() => {
            console.log('hello from constructor');
        });
    }
}
  • See also the angular documentation Lifecycle Hooks . 另请参阅角度文档Lifecycle Hooks
  • Do not forget to inject your dependencies like your myService instance, I added it to the constructor. 不要忘记像myService实例那样注入依赖项,我将它添加到构造函数中。

Testing 测试

I recommend you read over the Testing documentation . 我建议你阅读测试文档 It is a lot of information but it is worth it. 这是很多信息,但值得。 Here is code that you would use to unit test your component. 以下是用于对组件进行单元测试的代码。

let comp: MyComponent ;
let fixture: ComponentFixture<MyComponent>;

beforeEach(async(() => {
    TestBed.configureTestingModule({
        declarations: [MyComponent],
            providers: [
                { provide: MyService, useValue: {} }
            ]
        })
        .compileComponents(); 

    TestBed.compileComponents();
    fixture = TestBed.createComponent(MyComponent);
    comp = fixture.componentInstance;
}));


it('initializes the component', fakeAsync(() => {
    var service = TestBed.get(MyService); // get your service
    service.get = () => {
            return Promise.resolve(); // you can pass data here if the service returns something
        };

    // here you could add an expect to validate component state before the call or service completes

    comp.ngOnInit(); // call ngOnInit
    tick(); // simulate the promise being resolved

    expect(service.get.toHaveBeenCalled);
    // here you could add an expect to validate component state after the service completes
}));

Your constructor is executing before your tests, however, your constructor's code makes an async call to a service, and that is executed after your tests. 您的构造函数在测试之前正在执行,但是,构造函数的代码会对服务进行异步调用,并在测试之后执行。

First, you should really consider moving that service call away from the constructor. 首先,您应该考虑将该服务调用从构造函数中移除。

Second, when writing tests for a component you usually spy on service calls and check that they were called, you don't actually make the call, you mock it up. 其次,当你为一个组件编写测试时,你经常监视服务调用并检查它们是否被调用,你实际上并没有进行调用,你可以模拟它。 Look up the documentation for 'spyOn'. 查找“spyOn”的文档。

Lastly, if you want something to happen before your tests, take a look at 'beforeEach'. 最后,如果您想在测试之前发生某些事情,请查看'beforeEach'。 Anyways, hope this helps. 无论如何,希望这会有所帮助。

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

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