更改模拟服务在Angular / Jasmine / Redux中每个测试返回的可观察值

bub*_*ble 6 unit-testing jasmine karma-jasmine ngrx angular

我有一个返回由ngrx选择器公开的值的服务。组件定义此服务以获取数据。我正在使用服务的模拟为组件编写单元测试,并且我需要模拟服务为每个单元测试返回不同的值。我该如何实现?

零件

@Component({
    selector: 'app-test',
    templateUrl: './test.component.html',
    providers: [TestService],

})
    export class TestComponent {

        test$ = this.testService.test$;
        test: number;

        constructor(private service: TestService) {
            service.test$.subscribe(test => this.test = test);
        }
    }
Run Code Online (Sandbox Code Playgroud)

服务

export class TestService {

        test$ = this.store.select(getTestValueFromStore);

        constructor(private store: Store<any>){}
}
Run Code Online (Sandbox Code Playgroud)

尝试1(重置服务的值):不起作用

class MockTestService {
    **test$ = of(10);**
}

describe('TestComponent', () => {
    let testService: TestService;

    beforeEach((() => {
        // Define component service
        TestBed.overrideComponent(
            TestComponent,
            { set: { providers: [{ provide: TestService, useClass: MockTestService }] } }
        );

        TestBed.configureTestingModule({
            declarations: [TestComponent]
        })
            .compileComponents();
    }));

    beforeEach(async() => {
        fixture = TestBed.createComponent(TestComponent);
        component = fixture.componentInstance;
        testService = fixture.debugElement.injector.get(TestService);
        fixture.detectChanges();
    });

it('should do something when the value returned by the service is 20', fakeAsync(() => {

        **testService.test$ = of(20);**

        tick();

        expect(component.test).toEqual(20);
    }));
});
Run Code Online (Sandbox Code Playgroud)

尝试2:使用主题。业力引发错误“类型“可观察”的属性“下一个”不存在”,因为TestService返回的是可观察的而不是主题

class MockTestService {
        **test$ = new BehaviourSubject(10);**
    }

    describe('TestComponent', () => {
        let testService: TestService;

        beforeEach((() => {
            // Define component service
            TestBed.overrideComponent(
                TestComponent,
                { set: { providers: [{ provide: TestService, useClass: MockTestService }] } }
            );

            TestBed.configureTestingModule({
                declarations: [TestComponent]
            })
                .compileComponents();
        }));

        beforeEach(async() => {
            fixture = TestBed.createComponent(TestComponent);
            component = fixture.componentInstance;
            testService = fixture.debugElement.injector.get(TestService);
            fixture.detectChanges();
        });

    it('should do something when the value returned by the service is 20', fakeAsync(() => {

            **testService.test$.next(20);**

            tick();

            expect(component.test).toEqual(20);
        }));
    });
Run Code Online (Sandbox Code Playgroud)

dmc*_*dle 5

您在问题中说,您希望“模拟服务为每个单元测试返回不同的值”。为此,您将必须对定义组件的方式进行一些更改。

  1. 最重要的更改是将预订移到ngOnInit()中,并移出了组件的构造函数。如果这样做,则可以控制何时触发订阅,否则将在创建组件时触发订阅,这使得很难为每个单元测试返回不同的值。

  2. 完成此操作后,您需要小心致电fixture.detectChanges()。这是因为它将执行ngOnInit(),这将执行预订并将从Observable返回的值存储到中component.test。请注意,由于您正在使用of()它,因此只会发出一次然后完成。如果您将新值放入,它将不会再次发出testService.test$

  3. 设置完成后,您可以testService.test$在调用夹具.detectChanges之前更改值,然后根据需要进行更改。

我已经建立了一个StackBlitz来演示这一点,并尽可能少地更改代码以使其正常工作。有两个测试,每个测试返回不同的值。

我希望这有帮助!