gpt4 book ai didi

rxjs - 延迟测试 NGRX 效果

转载 作者:行者123 更新时间:2023-12-03 23:13:52 29 4
gpt4 key购买 nike

我想测试一个效果如下:

  • 如果调度了 LoadEntriesSucces 操作,则效果开始
  • 等待 5 秒
  • 5 秒后发送 http 请求
  • 当响应到达时,将分派(dispatch)新的操作(取决于响应是成功还是错误)。

  • Effect 的代码如下所示:
      @Effect()
    continuePollingEntries$ = this.actions$.pipe(
    ofType(SubnetBrowserApiActions.SubnetBrowserApiActionTypes.LoadEntriesSucces),
    delay(5000),
    switchMap(() => {
    return this.subnetBrowserService.getSubnetEntries().pipe(
    map((entries) => {
    return new SubnetBrowserApiActions.LoadEntriesSucces({ entries });
    }),
    catchError((error) => {
    return of(new SubnetBrowserApiActions.LoadEntriesFailure({ error }));
    }),
    );
    }),
    );

    我要测试的是效果是否在 5 秒后发送:
    it('should dispatch action after 5 seconds', () => {
    const entries: SubnetEntry[] = [{
    type: 'type',
    userText: 'userText',
    ipAddress: '0.0.0.0'
    }];

    const action = new SubnetBrowserApiActions.LoadEntriesSucces({entries});
    const completion = new SubnetBrowserApiActions.LoadEntriesSucces({entries});

    actions$ = hot('-a', { a: action });
    const response = cold('-a', {a: entries});
    const expected = cold('- 5s b ', { b: completion });

    subnetBrowserService.getSubnetEntries = () => (response);

    expect(effects.continuePollingEntries$).toBeObservable(expected);
    });

    但是这个测试对我不起作用。测试的输出如下所示:
    Expected $.length = 0 to equal 3.
    Expected $[0] = undefined to equal Object({ frame: 20, notification: Notification({ kind: 'N', value: undefined, error: undefined, hasValue: true }) }).
    Expected $[1] = undefined to equal Object({ frame: 30, notification: Notification({ kind: 'N', value: undefined, error: undefined, hasValue: true }) }).
    Expected $[2] = undefined to equal Object({ frame: 50, notification: Notification({ kind: 'N', value: LoadEntriesSucces({ payload: Object({ entries: [ Object({ type: 'type', userText: 'userText', ipAddress: '0.0.0.0' }) ] }), type: '[Subnet Browser API] Load Entries Succes' }), error: undefined, hasValue: true }) }).

    我应该怎么做才能使这个测试工作?

    最佳答案

    就像另一个答案中提到的那样,测试这种效果的一种方法是使用 TestScheduler 但它可以以更简单的方式完成。

    We can test our asynchronous RxJS code synchronously and deterministically by virtualizing time using the TestScheduler. ASCII marble diagrams provide a visual way for us to represent the behavior of an Observable. We can use them to assert that a particular Observable behaves as expected, as well as to create hot and cold Observables we can use as mocks.


    例如,让我们对以下效果进行单元测试:
    effectWithDelay$ = createEffect(() => {
    return this.actions$.pipe(
    ofType(fromFooActions.doSomething),
    delay(5000),
    switchMap(({ payload }) => {
    const { someData } = payload;

    return this.fooService.someMethod(someData).pipe(
    map(() => {
    return fromFooActions.doSomethingSuccess();
    }),
    catchError(() => {
    return of(fromFooActions.doSomethinfError());
    }),
    );
    }),
    );
    });
    效果只是在初始操作后等待 5 秒,然后调用一个服务,然后该服务将分派(dispatch)一个成功或错误操作。对该效果进行单元测试的代码如下:
    import { TestBed } from "@angular/core/testing";

    import { provideMockActions } from "@ngrx/effects/testing";

    import { Observable } from "rxjs";
    import { TestScheduler } from "rxjs/testing";

    import { FooEffects } from "./foo.effects";
    import { FooService } from "../services/foo.service";
    import * as fromFooActions from "../actions/foo.actions";

    // ...

    describe("FooEffects", () => {
    let actions$: Observable<unknown>;

    let testScheduler: TestScheduler; // <-- instance of the test scheduler

    let effects: FooEffects;
    let fooServiceMock: jasmine.SpyObj<FooService>;

    beforeEach(() => {
    // Initialize the TestScheduler instance passing a function to
    // compare if two objects are equal
    testScheduler = new TestScheduler((actual, expected) => {
    expect(actual).toEqual(expected);
    });

    TestBed.configureTestingModule({
    imports: [],
    providers: [
    FooEffects,
    provideMockActions(() => actions$),

    // Mock the service so that we can test if it was called
    // and if the right data was sent
    {
    provide: FooService,
    useValue: jasmine.createSpyObj("FooService", {
    someMethod: jasmine.createSpy(),
    }),
    },
    ],
    });

    effects = TestBed.inject(FooEffects);
    fooServiceMock = TestBed.inject(FooService);
    });

    describe("effectWithDelay$", () => {
    it("should dispatch doSomethingSuccess after 5 seconds if success", () => {
    const someDataMock = { someData: Math.random() * 100 };

    const initialAction = fromFooActions.doSomething(someDataMock);
    const expectedAction = fromFooActions.doSomethingSuccess();

    testScheduler.run((helpers) => {

    // When the code inside this callback is being executed, any operator
    // that uses timers/AsyncScheduler (like delay, debounceTime, etc) will
    // **automatically** use the TestScheduler instead, so that we have
    // "virtual time". You do not need to pass the TestScheduler to them,
    // like in the past.
    // https://rxjs-dev.firebaseapp.com/guide/testing/marble-testing

    const { hot, cold, expectObservable } = helpers;

    // Actions // -a-
    // Service // -b|
    // Results // 5s --c

    // Actions
    actions$ = hot("-a-", { a: initialAction });

    // Service
    fooServiceMock.someMethod.and.returnValue(cold("-b|", { b: null }));

    // Results
    expectObservable(effects.effectWithDelay$).toBe("5s --c", {
    c: expectedAction,
    });
    });

    // This needs to be outside of the run() callback
    // since it's executed synchronously :O
    expect(fooServiceMock.someMethod).toHaveBeenCalled();
    expect(fooServiceMock.someMethod).toHaveBeenCalledTimes(1);
    expect(fooServiceMock.someMethod).toHaveBeenCalledWith(someDataMock.someData);
    });
    });
    });

    请注意,在我使用的代码中 expectObservable使用 TestScheduler 实例中的“虚拟时间”来测试效果。

    关于rxjs - 延迟测试 NGRX 效果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54423862/

    29 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com