gpt4 book ai didi

testing - 如何在 ngrx 4 中正确测试效果?

转载 作者:行者123 更新时间:2023-11-28 20:05:39 25 4
gpt4 key购买 nike

有很多教程如何在 ngrx 3测试效果

但是,对于 ngrx4,我只发现了 1 或 2 个(他们通过 EffectsTestingModule 删除了经典方法),例如the official tutorial

但是,就我而言,他们的方法不起作用。

effects.spec.ts(在下面的链接中的 src/modules/list/store/list 下)

 describe('addItem$', () => {
it('should return LoadItemsSuccess action for each item', async() => {
const item = makeItem(Faker.random.word);
actions = hot('--a-', { a: new AddItem({ item })});

const expected = cold('--b', { b: new AddUpdateItemSuccess({ item }) });
// comparing marbles
expect(effects.addItem$).toBeObservable(expected);
});
})

effects.ts(在下面的链接中的 src/modules/list/store/list 下)

...
@Effect() addItem$ = this._actions$
.ofType(ADD_ITEM)
.map<AddItem, {item: Item}>(action => {
return action.payload
})
.mergeMap<{item: Item}, Observable<Item>>(payload => {
return Observable.fromPromise(this._listService.add(payload.item))
})
.map<any, AddUpdateItemSuccess>(item => {
return new AddUpdateItemSuccess({
item,
})
});
...

错误

 should return LoadItemsSuccess action for each item
Expected $.length = 0 to equal 1.
Expected $[0] = undefined to equal Object({ frame: 20, notification: Notification({ kind: 'N', value: AddUpdateItemSuccess({ payload: Object({ item: Object({ title: Function }) }), type: 'ADD_UPDATE_ITEM_SUCCESS' }), error: undefined, hasValue: true }) }).
at compare (webpack:///node_modules/jasmine-marbles/index.js:82:0 <- karma-test-shim.js:159059:33)
at Object.<anonymous> (webpack:///src/modules/list/store/list/effects.spec.ts:58:31 <- karma-test-shim.js:131230:42)
at step (karma-test-shim.js:131170:23)

注意:效果使用涉及写入 PouchDB 的服务。但是,这个问题似乎与此无关 并且效果在运行的应用程序中起作用

完整代码是一个 Ionic 3 应用程序,可以找到 here (只需克隆、npm i 和 npm run test)

更新:

对于 ReplaySubject 它有效,但不适用于热/冷弹珠

  const item = makeItem(Faker.random.word);
actions = new ReplaySubject(1) // = Observable + Observer, 1 = buffer size

actions.next(new AddItem({ item }));

effects.addItem$.subscribe(result => {
expect(result).toEqual(new AddUpdateItemSuccess({ item }));
});

最佳答案

@phillipzada 在 Github issue I posted. 上回答了我的问题

对于任何稍后检查这个的人,我在这里报告答案:

看起来这是一个使用 promises 和 marbles 的 RxJS 问题。 https://stackoverflow.com/a/46313743/4148561

我确实设法做了一些应该可行的 hack,但是,您将需要对正在调用的服务进行单独测试,除非您可以更新服务以返回可观察对象而不是 promise 。

本质上,我所做的是将 Observable.fromPromise 调用提取到它自己的“内部函数”中,我们可以模拟它来模拟对服务的调用,然后从那里查看。

这样您就可以在不使用弹珠的情况下测试内部函数 _addItem。

效果

import 'rxjs/add/observable/fromPromise';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/mergeMap';

import { Injectable } from '@angular/core';
import { Actions, Effect } from '@ngrx/effects';
import { Action } from '@ngrx/store';
import { Observable } from 'rxjs/Observable';

export const ADD_ITEM = 'Add Item';
export const ADD_UPDATE_ITEM_SUCCESS = 'Add Item Success';

export class AddItem implements Action {
type: string = ADD_ITEM;
constructor(public payload: { item: any }) { }
}

export class AddUpdateItemSuccess implements Action {
type: string = ADD_UPDATE_ITEM_SUCCESS;
constructor(public payload: { item: any }) { }
}

export class Item {

}

export class ListingService {
add(item: Item) {
return new Promise((resolve, reject) => { resolve(item); });
}
}

@Injectable()
export class SutEffect {

_addItem(payload: { item: Item }) {
return Observable.fromPromise(this._listService.add(payload.item));

}

@Effect() addItem$ = this._actions$
.ofType<AddItem>(ADD_ITEM)
.map(action => action.payload)
.mergeMap<{ item: Item }, Observable<Item>>(payload => {
return this._addItem(payload).map(item => new AddUpdateItemSuccess({
item,
}));
});

constructor(
private _actions$: Actions,
private _listService: ListingService) {

}
}

规范

import { cold, hot, getTestScheduler } from 'jasmine-marbles';
import { async, TestBed } from '@angular/core/testing';
import { Actions } from '@ngrx/effects';
import { Store, StoreModule } from '@ngrx/store';
import { getTestActions, TestActions } from 'app/tests/sut.helpers';

import { AddItem, AddUpdateItemSuccess, ListingService, SutEffect } from './sut.effect';
import { Observable } from 'rxjs/Observable';

import 'rxjs/add/observable/of';

describe('Effect Tests', () => {

let store: Store<any>;
let storeSpy: jasmine.Spy;

beforeEach(async(() => {

TestBed.configureTestingModule({
imports: [
StoreModule.forRoot({})
],
providers: [
SutEffect,
{
provide: ListingService,
useValue: jasmine.createSpyObj('ListingService', ['add'])
},
{
provide: Actions,
useFactory: getTestActions
}
]
});

store = TestBed.get(Store);
storeSpy = spyOn(store, 'dispatch').and.callThrough();
storeSpy = spyOn(store, 'select').and.callThrough();

}));

function setup() {
return {
effects: TestBed.get(SutEffect) as SutEffect,
listingService: TestBed.get(ListingService) as jasmine.SpyObj<ListingService>,
actions$: TestBed.get(Actions) as TestActions
};
}

fdescribe('addItem$', () => {
it('should return LoadItemsSuccess action for each item', async () => {

const { effects, listingService, actions$ } = setup();
const action = new AddItem({ item: 'test' });
const completion = new AddUpdateItemSuccess({ item: 'test' });

// mock this function which we can test later on, due to the promise issue
spyOn(effects, '_addItem').and.returnValue(Observable.of('test'));

actions$.stream = hot('-a|', { a: action });
const expected = cold('-b|', { b: completion });

expect(effects.addItem$).toBeObservable(expected);
expect(effects._addItem).toHaveBeenCalled();

});
})

})

helper

import { Actions } from '@ngrx/effects';
import { Observable } from 'rxjs/Observable';
import { empty } from 'rxjs/observable/empty';

export class TestActions extends Actions {
constructor() {
super(empty());
}
set stream(source: Observable<any>) {
this.source = source;
}
}

export function getTestActions() {
return new TestActions();
}

关于testing - 如何在 ngrx 4 中正确测试效果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46791909/

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