如何对从服务订阅 EventEmitter 的 Angular 组件进行单元测试?

问题描述

我有一个看起来像这样的组件:

export class MyComponent {
    myattr: boolean = true;
    constructor(public myService: MyService) {
        this.myService.stateUpdate.subscribe((event: number) => {
            this.myattr = event == 10;
        });
    }

服务:

export class MyService {
    stateUpdate: EventEmitter<number> = new EventEmitter<number>();
    onSomeEvent(): void {
        this.stateUpdate.emit(130);
    }
}

我的单元测试尝试:

    beforeEach(() => {
        fixture = Testbed.createComponent(MyComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
        component.myService = new MyService();
    });
    it("emitting 130 should set myattr to false",async()=>{
        component.myService.stateUpdate.subscribe((event: number) => {
            expect(event).toEqual(130); // this is detected correctly
        })
        component.myService.onSomeEvent();
        fixture.whenStable();
        expect(component.myattr).toEqual(false); // this does not work
    });

基本上,我想测试当 subscribe 中的任何代码完成执行时会发生什么。我该怎么做?

谢谢

解决方法

在您的示例中,您创建服务并在创建组件后将其分配给 myService 属性,因此构造函数中的订阅是在另一个服务实例上进行的。 您可以在测试文件中创建服务实例或创建它的模拟,并在配置测试床时通过 MyService 令牌提供它。因此,您以后可以访问该实例并在其上发出事件

,

你必须在 fixture.whenStable().then() 内做你的断言

it("emitting 130 should set myattr to false",async(()=>{
    component.myService.onSomeEvent();
    fixture.whenStable().then(() => {
        expect(component.myattr).toEqual(false);
    });
});

请注意,Angular 的 async() 被替换为 waitForAsync()

,

在 Angular 官方文档中有一整节可能有帮助的常见测试场景:

https://angular.io/guide/testing-components-scenarios

在您的特定情况下,请查看这两个小节以获取完整的示例说明:

https://angular.io/guide/testing-components-scenarios#component-with-a-dependency

https://angular.io/guide/testing-components-scenarios#component-with-async-service

有不同的方法,但我通常做的是提供一个带有测试主题的服务存根来发出值,然后在测试用例中使用 async 关键字,以便我可以在发出时预期结果。