• 测试复杂的 Actions
    • 条件 Action
    • 异步 Action

    测试复杂的 Actions

    当我们想测试异步或条件Actions创建者时,事情变得有点棘手。我们的目标仍然是相同的:确保 operations 发出我们期望的Actions。

    条件 Action

    考虑以下条件action(即,根据当前状态触发的操作):

    1. import { Injectable } from '@angular/core';
    2. import { NgRedux } from 'ng2-redux';
    3. export const INCREMENT_COUNTER = 'INCREMENT_COUNTER';
    4. @Injectable()
    5. export class MyActionService {
    6. constructor(private redux: NgRedux) {};
    7. // A conditional action
    8. incrementIfOdd() {
    9. const { counter } = this.redux.getState();
    10. if (counter % 2 === 0) return;
    11. this.redux.dispatch({ type: INCREMENT_COUNTER });
    12. }
    13. }

    单元测试与之前类似,但我们需要模拟我们的状态以及dispatch:

    1. import { NgRedux } from 'ng2-redux';
    2. import { CounterActions } from './counter';
    3. class MockRedux extends NgRedux<any> {
    4. constructor(private state: any) {
    5. super(null);
    6. }
    7. dispatch = () => undefined;
    8. getState = () => this.state;
    9. }
    10. describe('counter action creators', () => {
    11. let actions: CounterActions;
    12. let mockRedux: NgRedux<any>;
    13. let mockState: any = {};
    14. beforeEach(() => {
    15. // Our mock NgRedux can now accept mock state as a constructor param.
    16. mockRedux = new MockRedux(mockState);
    17. actions = new CounterActions(mockRedux);
    18. });
    19. it('incrementIfOdd should dispatch INCREMENT_COUNTER action if count is odd',
    20. () => {
    21. // Our tests can bake in the initial state they need.
    22. const expectedAction = {
    23. type: CounterActions.INCREMENT_COUNTER
    24. };
    25. mockState.counter = 3;
    26. spyOn(mockRedux, 'dispatch');
    27. actions.incrementIfOdd();
    28. expect(mockRedux.dispatch).toHaveBeenCalled();
    29. expect(mockRedux.dispatch).toHaveBeenCalledWith(expectedAction);
    30. });
    31. it('incrementIfOdd should not dispatch INCREMENT_COUNTER action if count is even',
    32. () => {
    33. mockState.counter = 2;
    34. spyOn(mockRedux, 'dispatch');
    35. actions.incrementIfOdd();
    36. expect(mockRedux.dispatch).not.toHaveBeenCalled();
    37. });
    38. });

    异步 Action

    下面异步Action怎么办?

    1. import { Injectable } from '@angular/core';
    2. import { NgRedux } from 'ng2-redux';
    3. export const INCREMENT_COUNTER = 'INCREMENT_COUNTER';
    4. export const DECREMENT_COUNTER = 'DECREMENT_COUNTER';
    5. @Injectable()
    6. export class CounterActions {
    7. constructor(private redux: NgRedux<any>) {}
    8. // ...
    9. incrementAsync(timeInMs = 1000) {
    10. this.delay(timeInMs).then(() => this.redux.dispatch({ type: INCREMENT_COUNTER }));
    11. }
    12. private delay(timeInMs) {
    13. return new Promise((resolve,reject) => {
    14. setTimeout(() => resolve() , timeInMs);
    15. });
    16. }
    17. }

    我们可以使用异步服务函数的常规技术来测试:

    • 如果我们可以让incrementAsync返回一个promise,我们可以从测试中返回一个promise,并且jasmine将一直等到它完成。
    • 或者,我们可以使用在测试组件一节中讨论的fakeAsync技术。

    要记住的是,如果我们遵循ActionCreatorService模式,我们的操作只是Angular服务上的函数。 所以我们可以模拟出NgRedux(和任何其他依赖项),就像测试其他Angular 2服务一样。