【问题标题】:How to mock observable from service in marble testing如何在大理石测试中从服务中模拟 observable
【发布时间】:2022-02-06 00:41:36
【问题描述】:

我想测试一个包含我的逻辑的 Angular 服务。我将简化我的案例以使其简单明了:

我有我想要测试的 logic$,它绑定到 data$,另一个 observable

@Injectable({
    providedIn: 'root',
})
export class MyService {
    readonly data = new BehaviorSubject<string>('');
    readonly data$ = this.data.asObservable();

    readonly logic$ = this.data$.pipe(
        map((logic: string) => `Mighty ${logic}`)
    )

    constructor() {}
}

我希望能够在我的测试中模拟数据并查看我的逻辑是否按预期运行

describe('MyService', () => {
    let myService: MyService;

    const testScheduler = new TestScheduler((actual, expected) => {
        expect(actual).toEqual(expected);
    });

    beforeEach(() => {
        myService = new MyService();
        myService.data$ = of("foo", "bar");
        TestBed.configureTestingModule({
            providers: [{ provide: MyService, useValue: myService }]
        });
    });

    it('should be created', inject([MyService], (service: MyService) => {
        expect(service).toBeTruthy();
    }));

    it('should be toto lala', inject([MyService], (service: MyService) => {
        testScheduler.run(helpers => {
            const { expectObservable, cold } = helpers;
            const expect$ = "ab";
            expectObservable(service.logic$).toBe(expect$, {
                a: "Mighty foo",
                b: "Mighty bar",
            })
        });
    }));
});

我收到以下错误:

    Chrome Headless 97.0.4692.99 (Windows 10) MyService should be toto lala FAILED
            Expected $.length = 1 to equal 2.
            Expected $[0].notification.value = 'Mighty ' to equal 'Mighty foo'.
            Expected $[1] = undefined to equal Object({ frame: 1, notification: Notification({ kind: 'N', value: 'Mighty bar', error: undefined, hasValue: true }) }).
            Error: Expected $.length = 1 to equal 2.
            Expected $[0].notification.value = 'Mighty ' to equal 'Mighty foo'.
            Expected $[1] = undefined to equal Object({ frame: 1, notification: Notification({ kind: 'N', value: 'Mighty bar', error: undefined, hasValue: true }) }).
                at <Jasmine>
                at TestScheduler.assertDeepEqual (projects/ui-affaire-client/src/lib/components/my-component/my-component.service.spec.ts:11:20)
                at node_modules/rxjs/_esm2015/internal/testing/TestScheduler.js:110:1
                at <Jasmine>
    Chrome Headless 97.0.4692.99 (Windows 10): Executed 2 of 3 (1 FAILED) (0 secs / 0.028 secs)
    Chrome Headless 97.0.4692.99 (Windows 10) MyService should be toto lala FAILED
            Expected $.length = 1 to equal 2.
            Expected $[0].notification.value = 'Mighty ' to equal 'Mighty foo'.
            Expected $[1] = undefined to equal Object({ frame: 1, notification: Notification({ kind: 'N', value: 'Mighty bar', error: undefined, hasValue: true }) }).
            Error: Expected $.length = 1 to equal 2.
            Expected $[0].notification.value = 'Mighty ' to equal 'Mighty foo'.
            Expected $[1] = undefined to equal Object({ frame: 1, notification: Notification({ kind: 'N', value: 'Mighty bar', error: undefined, hasValue: true }) }).
                at <Jasmine>
                at TestScheduler.assertDeepEqual (projects/ui-affaire-client/src/lib/components/my-component/my-component.service.spec.ts:11:20)
                at node_modules/rxjs/_esm2015/internal/testing/TestScheduler.js:110:1
    Chrome 97.0.4692.99 (Windows 10) MyService should be toto lala FAILED
            Expected $.length = 1 to equal 2.
            Expected $[0].notification.value = 'Mighty ' to equal 'Mighty foo'.
            Expected $[1] = undefined to equal Object({ frame: 1, notification: Notification({ kind: 'N', value: 'Mighty bar', error: undefined, hasValue: true }) }).
            Error: Expected $.length = 1 to equal 2.
            Expected $[0].notification.value = 'Mighty ' to equal 'Mighty foo'.
            Expected $[1] = undefined to equal Object({ frame: 1, notification: Notification({ kind: 'N', value: 'Mighty bar', error: undefined, hasValue: true }) }).
                at <Jasmine>
                at TestScheduler.assertDeepEqual (projects/ui-affaire-client/src/lib/components/my-component/my-component.service.spec.ts:11:20)
                at node_modules/rxjs/_esm2015/internal/testing/TestScheduler.js:110:1
                at <Jasmine>
    Chrome Headless 97.0.4692.99 (Windows 10): Executed 2 of 3 (1 FAILED) (skipped 1) (0.097 secs / 0.028 secs)
    Chrome 97.0.4692.99 (Windows 10): Executed 1 of 3 (1 FAILED) (0 secs / 0.019 secs)
    Chrome 97.0.4692.99 (Windows 10) MyService should be toto lala FAILED
            Expected $.length = 1 to equal 2.
            Expected $[0].notification.value = 'Mighty ' to equal 'Mighty foo'.
            Expected $[1] = undefined to equal Object({ frame: 1, notification: Notification({ kind: 'N', value: 'Mighty bar', error: undefined, hasValue: true }) }).
            Error: Expected $.length = 1 to equal 2.
            Expected $[0].notification.value = 'Mighty ' to equal 'Mighty foo'.
            Expected $[1] = undefined to equal Object({ frame: 1, notification: Notification({ kind: 'N', value: 'Mighty bar', error: undefined, hasValue: true }) }).
                at <Jasmine>
                at TestScheduler.assertDeepEqual (projects/ui-affaire-client/src/lib/components/my-component/my-component.service.spec.ts:11:20)
    Chrome Headless 97.0.4692.99 (Windows 10): Executed 2 of 3 (1 FAILED) (skipped 1) (0.097 secs / 0.028 secs)
    Chrome 97.0.4692.99 (Windows 10): Executed 2 of 3 (1 FAILED) (skipped 1) (0.099 secs / 0.026 secs)
    TOTAL: 2 FAILED, 2 SUCCESS
    TOTAL: 2 FAILED, 2 SUCCESS

据我所知,显然我的模拟不起作用。 logic$ 的长度为 1,数据仅发出 '' (由 behaviorSubject 发出) 我的猜测是我的模拟是在服务创建之后完成的,因此“旧”的 observables 仍然被使用而不是被替换。

有没有办法正确替换 observable 来测试服务中的逻辑?

【问题讨论】:

    标签: angular unit-testing rxjs jasmine-marbles rxjs-marbles


    【解决方案1】:

    当您创建MyService 的新实例时,属性logic$ 将使用data$初始值 进行分配。

    即使您之后更改data$ 的值,logic$ 属性也不会被重新评估,因此它将保持相同的初始值(使用 BehaviorSubject 作为源)。

    要使用弹珠测试logic$,您可以执行以下操作:

    it('should be toto lala', inject([MyService], (service: MyService) => {
      testScheduler.run((helpers) => {
        const { expectObservable, cold } = helpers;
        const sourceMarbles =   '-1-2';
        const expectedMarbles = 'ia-b';
    
        // create cold obs as source
        const source = cold(sourceMarbles, { 1: 'foo', 2: 'bar' });
    
        // subscribe BehaviourSubject to source to relay emitted values
        source.subscribe(service.data);
        
    
        // test the output of logic$
        expectObservable(service.logic$).toBe(expectedMarbles, {
          i: 'Mighty ', // <- this accounts for the initial value of the Behavior
          a: 'Mighty foo',
          b: 'Mighty bar',
        });
      });
    }));
    

    干杯

    【讨论】:

      猜你喜欢
      • 2019-03-16
      • 2019-04-18
      • 1970-01-01
      • 2021-09-18
      • 2020-03-04
      • 2015-07-07
      • 1970-01-01
      • 1970-01-01
      • 2017-07-01
      相关资源
      最近更新 更多