【发布时间】:2019-09-30 21:39:45
【问题描述】:
我有一个@Effect,它使用MemoizedSelector 从redux 存储中获取一个项目,并使用mergeMap 它和一个Action 的有效负载。效果很好,但是为此设置 Jest 测试证明很困难,因为我似乎无法模拟选择器的返回值,因为 select 是一个已声明的导入函数(来自 '@ngrx/store ') 并在效果中使用,并且选择器本身也是一个导入函数。我现在正抓着稻草。
如何编写单元测试来测试使用商店选择器的 NGRX 效果?
"@ngrx/store": "^7.4.0",
"rxjs": "^6.2.2"
我尝试了以下几种解决方案:
- 使用
provideMockStore({
initialState
})
provideMockStore 来自'@ngrx/store/testing';,其中初始状态既是我的实际 initialState,也是包含我要选择的确切结构/项目的状态
-
使用来自各种 SO 问题/答案的不同类型的
MockStore以及不同的博客文章方法 尝试使用
<selector>.projector(<my-mock-object>)模拟选择器(这里是草根,我很确定这将用于选择器而不是效果的隔离测试)
效果本身:
@Effect()
getReviewsSuccess$ = this.actions$.pipe(
ofType<ProductActions.GetReviewsSuccess>(
ProductActions.ProductActionTypes.GET_REVIEWS_SUCCESS
),
mergeMap(() => this.reduxStore.pipe(select(selectProduct))),
map(({ product_id }) => product_id),
map(product_id => new ProductActions.GetReviewsMeta({
product_id,
}))
);
规格:
......
let effects: ProductEffects;
let facade: Facade;
let actions$: Observable<any>;
let store$: Observable<State>;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule,
// ^ I've also tried using StoreModule.forRoot(...) here to configure
// it in similar fashion to the module where this effect lives
],
providers: [
ProductEffects,
provideMockActions(() => actions$),
{
provide: Facade,
useValue: facadeServiceMock,
},
ResponseService,
provideMockStore({
initialState
})
// ^ also tried setting up the test with different variations of initialState
],
});
......
it('should return a GetReviewsMeta on successful GetReviewsSuccess', () => {
const reviews = {...reviewListMock};
const { product_id } = {...productMockFull};
const action = new ProductActions.GetReviewsSuccess({
reviews
});
const outcome = new ProductActions.GetReviewsMeta({
product_id
});
actions$ = hot('-a', { a: action });
// store$ = cold('-c', { c: product_id });
// not sure what, if anything I need to do here to mock select(selectProduct)
const expected = cold('-b', { b: outcome });
expect(effects.getReviewsSuccess$).toBeObservable(expected);
});
选择器selectProduct:
export const getProduct = ({product}: fromProducts.State) => product;
export const getProductState = createFeatureSelector<
fromProducts.State
>('product');
export const selectProduct = createSelector(
getProductState,
getProduct,
);
我希望测试通过,但我不断收到以下错误
● Product Effects › should return a GetReviewsMeta on successful GetReviewsSuccess
expect(received).toBeNotifications(expected)
Expected notifications to be:
[{"frame": 10, "notification": {"error": undefined, "hasValue": true, "kind": "N", "value": {"payload": {"product_id": 2521}, "type": "[Reviews] Get Reviews Meta"}}}]
But got:
[{"frame": 10, "notification": {"error": [TypeError: Cannot read property 'product_id' of undefined], "hasValue": false, "kind": "E", "value": undefined}}]
显然MemoizedSelector (selectProduct) 不知道应该在商店中的产品对象是什么(但似乎不知道我是否注入了具有它的initialState)并且可以'无法获得产品的product_id,因为我没有在beforeEach 或规范本身中正确设置它...
【问题讨论】:
标签: angular rxjs ngrx ngrx-effects