[英]How to mock @ngrx/store state in Angular 4 unit tests
我正在使用@ngrx / store和@ngrx / effect開發一個Angular 4應用程序,我正在嘗試為我的效果編寫一些單元測試。
我的一個效果應該是使用服務從后端獲取一些數據。 從后端檢索值后,應每隔一段時間觸發此效果,以生成輪詢效果並更新本地數據。
由於輪詢間隔是在我的應用程序狀態配置的,我希望能夠模擬狀態存儲,以便我可以在測試期間更改它。
這是我的SPEC:
describe('Order Effects', () => {
let actions: Observable<any>;
let effects: OrderEffect;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
StoreModule.forRoot({ orders: ordersReducer })
],
providers: [
OrderEffect,
provideMockActions(() => actions),
{ provide: OrderService, useValue: jasmine.createSpyObj('orderService', ['getAllOrders']) }
]
});
effects = TestBed.get(OrderEffect);
});
it('should load orders and call load orders complete action', () => {
const mockData = [{ id: 1 }, { id: 2 }, { id: 3 }];
const orderService = TestBed.get(OrderService);
orderService.getAllOrders.and.returnValue(Observable.of(mockData));
actions = hot('--a-', { a: new orderActions.LoadAllOrdersAction(new Date()) });
const expectedEffect = cold('--b|', { b: new orderActions.LoadAllOrdersCompleteAction(mockData) });
expect(effects.loadAllOrders$).toBeObservable(expectedEffect);
});
});
這是效果:
@Injectable()
export class OrderEffect {
@Effect()
loadAllOrders$: Observable<Action> = this.actions.ofType(orderActions.LOAD_ALL_ORDERS)
.withLatestFrom(this.store$) // Get the latest state from the store and add as the second value of the array below
.switchMap((input: any[]) => {
const action: orderActions.LoadAllOrdersAction = input[0];
const store: AppState = input[1];
return Observable.timer(0, store.orders.pollingInterval) // Timer to create the polling effect.
.switchMap(() => this.orderService.getAllOrders(action.payload)
.map((orders: Array<any>) => new orderActions.LoadAllOrdersCompleteAction(orders))
.catch(error => Observable.throw(new orderActions.LoadAllOrdersFailAction(error)))
);
});
constructor(private actions: Actions, private orderService: OrderService, private store$: Store<AppState>) { }
}
在效果代碼中,我使用: .withLatestFrom(this.store$)
獲取當前狀態,我想模擬這個屬性: store.orders.pollingInterval
。 誰能幫我?
如果您需要獲得效果中的商店狀態,則在測試此效果時必須監視商店,以便您可以模擬其狀態。
describe('Order Effects', () => {
// ...
let ordersStateMock = {
orders: {
pollingInterval: null
}
};
beforeEach(() => {
const storeSpy = jasmine.createSpyObj('storeSpy', [
'dispatch', 'subscribe'
]);
storeSpy.select = () => Observable.of(ordersStateMock);
// ...
});
});
然后在您所在的州,您可以為商店狀態設置所需的值:
it('should load orders and call load orders complete action', () => {
// ...
ordersStateMock.orders.pollingInterval = 2;
actions = hot('--a-', { a: new orderActions.LoadAllOrdersAction(new Date()) });
// ...
});
我在測試中使用此解決方案。 我在“使用Angular和ngrx進行反應性編程”一書中得到了它。 它指的是ngrx和Angular v2,但它仍然非常有用,因為它解釋了反應式編程和關鍵特性的概念。
希望這可以幫助!
我一直在查看@ngrx文檔,我找到了另一個模擬商店狀態的可能答案(參見下面的完整代碼):
let actions;
let effects: OrderEffect;
let ordersStateMock;
beforeEach(() => {
ordersStateMock = {
orders: {
pollingInterval: 30
}
};
TestBed.configureTestingModule({
imports: [
StoreModule.forRoot(
{ orders: ordersReducer },
{ initialState: ordersStateMock }
)
],
providers: [
OrderEffect,
provideMockActions(() => actions),
{ provide: OrderService,
useValue: jasmine.createSpyObj('orderService', ['getAllOrders'])
}
]
});
effects = TestBed.get(OrderEffect);
});
顯然我只需要在StoreModule
導入中設置初始狀態。
建議的解決方案對我不起作用。 我使用的是ngrx 5.2.0(帶有ngrx實體)和Angular 5.2.9。 metaReducer的想法如下所述: https : //github.com/ngrx/platform/issues/414#issuecomment-331354701
在我的情況下,我想模仿一些狀態。 所以我的metaReducer看起來像:
export function mockMetaReducer(reducer: ActionReducer<any>): ActionReducer<any, any> {
return function(state: any, action: any): any {
return reducer(ordersStateMock, action);
};
}
這個解決方案是最簡單的,適用於ngrx:5.2.0
為基於真實商店的商店創建模擬
export class StoreMock<T = any> extends Store<T> {
public source = new BehaviorSubject<any>({});
public overrideState(allStates: any) {
this.source.next(allStates);
}
}
並在測試中使用它
let store: StoreMock<YourStateModel>;
TestBed.configureTestingModule({
providers: [
{ provide: Store, useClass: StoreMock },
]
});
store = TestBed.get(Store);
beforeEach(() => {
store.overrideState({
currentStateName: MOCKED_STATE_DATA_OBJECT
});
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.