0

我想让使用 Jasmine 和 Marbles 更轻松地为我的应用程序效果创建测试。
为此,我想创建几个函数以在每个测试中导入,以减少代码重复并提高测试的可读性。

所以让我们假设我有这三个文件:

效果文件

@Injectable()
export class CustomEffects {
    customEffect$ = createEffect(() => {
        this.actions$.pipe(
            ofType(customActions.customAction),
            map(action => customActions.otherAction({name: 'name'}))
        )
    });

    constructor(private actions$: Actions) {}
}

测试文件

describe('CustomEffects', () => {
    let effects: CustomEffects;
    let actions: Observable<Action>;

    beforeEach(() => {
        TestBed.configureTestingModule(effectsTestingMOduleConfiguration(
            CustomEffects,
            provideMockActions(() => actions)
        ));
        
        actions = TestBed.inject(Actions);
        effects = TestBed.inject(CustomEffects);
    });

    afterEach(() => {
        TestBed.resetTestingModule();
    });

    it('effect customEffect$ should return otherAction', () => {
        const inputAction = customActions.customAction();
        const expectedActions = [
            customActions.otherAction({name: 'name'})
        ];
        testEffect(actions, effects, 'customEffect$', inputAction, expectedActions);
    });
});

函数文件

export function effectsTestingMOduleConfiguration(effects: any, ...apiService: any) {
    const providers = [effects];
    if(apiService) {
        providers.push(apiService);
    }
    return {providers}
}

export function testEffect<T>(actions: Observable<Action>, effects: T, effectName: keyof T, inputAction: Action, expectedActions: Action[]) {
    const actionMarbles: {[marble: string]: Action};
    const firstLetter = 'b'.charCodeAt(0);
    const letters = expectedActions.map((_, index) => String.fromCharCode(firstLetter + index));
    const marbles = '-(' + letters.reduce((prev, curr) => prev + curr, '') + ')';
    letters.forEach(letter => actionMarbles[letter] = expectedActions[letter.charCodeAt(0) - firstLetter]);
    actions = hot('-a', {a: inputAction});
    const expectedResult = cold(marbles, actionMarbles);
    expect(effects[effectName]).toBeObservable(expectedResult);
}

对我来说,这看起来应该可以正常工作,但是测试失败并显示以下消息:

Expected: -(b),
Received: ,

Expected: [{
  "frame": 10,
  "notification": {
    "kind": "N",
    "value": {
      "name": "name",
      "type": "[CustomActions] Custom Action"
    },
    "hasValue": true
  }
}]
Received: []

但是,如果我像这样更改我的测试文件:

describe('CustomEffects', () => {
    let effects: CustomEffects;
    let actions: Observable<Action>;

    beforeEach(() => {
        TestBed.configureTestingModule(effectsTestingMOduleConfiguration(
            CustomEffects,
            provideMockActions(() => actions)
        ));
        
        actions = TestBed.inject(Actions);
        effects = TestBed.inject(CustomEffects);
    });

    afterEach(() => {
        TestBed.resetTestingModule();
    });

    it('effect customEffect$ should return otherAction', () => {
        const inputAction = customActions.customAction();
        const expectedActions = [
            customActions.otherAction({name: 'name'})
        ];
        actions = hot('-a', {a: inputAction});
        const expectedResult = cold('-(b)', {b: expectedActions[0]});
        expect(effects['customEffect$']).toBeObservable(expectedResult);
    });
});

或者像这样:

describe('CustomEffects', () => {
    let effects: CustomEffects;
    let actions: Observable<Action>;

    beforeEach(() => {
        TestBed.configureTestingModule(effectsTestingMOduleConfiguration(
            CustomEffects,
            provideMockActions(() => actions)
        ));
        
        actions = TestBed.inject(Actions);
        effects = TestBed.inject(CustomEffects);
    });

    afterEach(() => {
        TestBed.resetTestingModule();
    });

    it('effect customEffect$ should return otherAction', () => {
        const inputAction = customActions.customAction();
        const expectedActions = [
            customActions.otherAction({name: 'name'})
        ];
        testEffect(effects, 'customEffect$', inputAction, expectedActions);
    });

    function testEffect<T>(effects: T, effectName: keyof T, inputAction: Action, expectedActions: Action[]) {
        const actionMarbles: {[marble: string]: Action};
        const firstLetter = 'b'.charCodeAt(0);
        const letters = expectedActions.map((_, index) => String.fromCharCode(firstLetter + index));
        const marbles = '-(' + letters.reduce((prev, curr) => prev + curr, '') + ')';
        letters.forEach(letter => actionMarbles[letter] = expectedActions[letter.charCodeAt(0) - firstLetter]);
        actions = hot('-a', {a: inputAction});
        const expectedResult = cold(marbles, actionMarbles);
        expect(effects[effectName]).toBeObservable(expectedResult);
    }
});

测试现在将毫无问题地通过。

所以我想做的是让函数testEffect正常工作,如果可能的话,改变函数effectsTestingMOduleConfiguration这样就不需要手动传递provideMockActions(() => actions)了。

4

0 回答 0