Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angular/31.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Angular 如何在角4单元测试中模拟@ngrx/存储状态_Angular_Unit Testing_Jasmine - Fatal编程技术网

Angular 如何在角4单元测试中模拟@ngrx/存储状态

Angular 如何在角4单元测试中模拟@ngrx/存储状态,angular,unit-testing,jasmine,Angular,Unit Testing,Jasmine,我正在使用@ngrx/store和@ngrx/effect开发一个Angular 4应用程序,我正在尝试为我的效果编写一些单元测试 我的一个特效应该是使用服务从后端获取一些数据。从后端检索到值后,应每隔一段时间触发此效果,以生成轮询效果并更新本地数据 由于轮询间隔是根据应用程序的状态配置的,因此我希望能够模拟状态存储,以便在测试期间更改它 这是我的规格: description('Order Effects',()=>{ 让行动:可观察; let效应:有序效应; 在每个之前(()=>{ Test

我正在使用@ngrx/store和@ngrx/effect开发一个Angular 4应用程序,我正在尝试为我的效果编写一些单元测试

我的一个特效应该是使用服务从后端获取一些数据。从后端检索到值后,应每隔一段时间触发此效果,以生成轮询效果并更新本地数据

由于轮询间隔是根据应用程序的状态配置的,因此我希望能够模拟状态存储,以便在测试期间更改它

这是我的规格:

description('Order Effects',()=>{
让行动:可观察;
let效应:有序效应;
在每个之前(()=>{
TestBed.configureTestingModule({
进口:[
forRoot({orders:ordersReducer})
],
供应商:[
秩序效应,
提供打包操作(()=>操作),
{provide:OrderService,useValue:jasmine.createSpyObj('OrderService',['getAllOrders'])}
]
});
effects=TestBed.get(OrderEffect);
});
它('应加载订单并调用加载订单完成操作',()=>{
const mockData=[{id:1},{id:2},{id:3}];
const orderService=TestBed.get(orderService);
orderService.getAllOrders.and.returnValue(mockData的可观察值);
actions=hot('--a-',{a:neworderactions.LoadAllOrdersAction(new Date())});
const expectedEffect=cold('--b |',{b:neworderactions.LoadAllOrdersCompleteAction(mockData)});
expect(effects.loadAllOrders$).tobeobbservable(expectedEffect);
});
});
效果如下:

@Injectable()
导出类OrderEffect{
@效果()
loadAllOrders$:Observable=this.actions.ofType(orderActions.LOAD\u ALL\u订单)
.withLatestFrom(this.store$)//从存储获取最新状态,并添加为下面数组的第二个值
.switchMap((输入:any[])=>{
常量操作:orderActions.LoadAllOrdersAction=输入[0];
常量存储:AppState=input[1];
return Observable.timer(0,store.orders.pollingInterval)//创建轮询效果的计时器。
.switchMap(()=>this.orderService.getAllOrders(action.payload)
.map((订单:数组)=>new orderActions.LoadAllOrdersCompleteTAction(订单))
.catch(错误=>Observable.throw(新的orderActions.LoadAllOrdersFailAction(错误)))
);
});
构造函数(私有操作:操作,私有orderService:orderService,私有存储$:存储){}
}

在效果代码中,我使用:
.withLatestFrom(this.store$)
获取当前状态,我想模拟此属性:
store.orders.pollingInterval
。有人能帮我吗?

如果你需要获得商店状态的效果,你必须在测试该效果时监视商店,以便模拟其状态

description('Order Effects',()=>{
// ...
让ordersStateMock={
订单:{
pollingInterval:null
}
};
在每个之前(()=>{
const storeSpy=jasmine.createSpyObj('storeSpy'[
“发送”、“订阅”
]);
storeSpy.select=()=>Observable.of(ordersStateMock);
// ...
});
});
然后,在您的状态中,您可以为存储状态设置所需的值:

it('should load orders and call load orders complete action',()=>{
// ...
ordersStateMock.orders.pollingInterval=2;
actions=hot('--a-',{a:neworderactions.LoadAllOrdersAction(new Date())});
// ...
});
我在测试中使用这个解决方案。我在《Angular和ngrx的反应式编程》一书中得到了它。它指的是ngrx和Angular v2,但它仍然非常有用,因为它解释了反应式编程的概念和关键功能


希望这有帮助

我一直在看@ngrx文档,我找到了模拟商店状态的另一个可能答案(请参阅下面的完整代码):


显然,我只需要在
StoreModule
导入中设置初始状态。

建议的解决方案对我不起作用。我使用的是ngrx 5.2.0(带有ngrx实体)和Angular 5.2.9。metaReducer的想法如下所述:

在我的情况下,我想嘲笑一些国家。所以我的metaReducer看起来像:

  export function mockMetaReducer(reducer: ActionReducer<any>): ActionReducer<any, any> {
    return function(state: any, action: any): any {
      return reducer(ordersStateMock, action);
    };
  }
导出函数mockMetaReducer(reducer:ActionReducer):ActionReducer{ 返回函数(状态:任意,操作:任意):任意{ 返回减速机(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);
    }

}
导出类StoreMock扩展存储{
public source=新的行为主体({});
公共财产(所有州:任何){
this.source.next(所有州);
}
}
并在测试中使用它

let store: StoreMock<YourStateModel>;

TestBed.configureTestingModule({
    providers: [
        { provide: Store, useClass: StoreMock },
    ]
});
store = TestBed.get(Store);


beforeEach(() => {
    store.overrideState({
        currentStateName: MOCKED_STATE_DATA_OBJECT
    });
});
let-store:StoreMock;
TestBed.configureTestingModule({
供应商:[
{provide:Store,useClass:StoreMock},
]
});
store=TestBed.get(store);
在每个之前(()=>{
商店地产({
currentStateName:模拟的\u状态\u数据\u对象
});
});

你好,谢谢你的回答!我按照你的建议做了,但事情仍然不起作用。我知道存储状态也是可观察的,但是如何告诉@ngrx使用我的模拟状态呢?我试图将我的导入行更改为:
StoreModule.forRoot({orders:ordersReducer,config:{initialState:storeSpy}}})
,但它不起作用。我在测试中以这种方式提供存储:
TestBed.configureTestingModule({providers:[{provide:store,useValue:storeSpy}}})
Hi,我试着用你的方式提供商店,但没有成功。我遇到了以下错误:
TypeError:您提供了一个无效的对象,其中需要一个流。您可以提供一个可观察的、承诺的、数组的或可观察的。
我继续我的测试,我提供了一个
可观察的
,而不是
spyobj
和ev
let store: StoreMock<YourStateModel>;

TestBed.configureTestingModule({
    providers: [
        { provide: Store, useClass: StoreMock },
    ]
});
store = TestBed.get(Store);


beforeEach(() => {
    store.overrideState({
        currentStateName: MOCKED_STATE_DATA_OBJECT
    });
});