首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >模拟ngrx/store

模拟ngrx/store
EN

Stack Overflow用户
提问于 2016-11-29 12:31:52
回答 3查看 7.2K关注 0票数 9

这是关于Angular 2官方发布的。我知道单元测试在beta、RC和官方发布版之间发生了巨大的变化。

当@ngrx/store被用作构造函数中的参数时,在单元测试中模拟它的好方法是什么?它不像模仿一个服务那么简单。

例如,如果我想模拟一个服务,那么我可以这样做:

代码语言:javascript
复制
let serviceStub = { }; // not a true mocked service, just a stub, right?

let de: DebugElement;
let el: HTMLElement;
let nativeEl: Element;
let comp: Typeahead;
let fixture: ComponentFixture<Typeahead>;

describe('Component:Typeahead', () => {
    beforeEach(() => {
        TestBed.configureTestingModule({
            imports: [...],
            declarations: [Typeahead],
            providers: [
                {provide: TypeaheadService, useValue: serviceStub} // provides the service that is being "mocked"
            ]
        }).compileComponents();

        fixture = TestBed.createComponent(Typeahead);
        nativeEl = fixture.nativeElement;
        comp = fixture.componentInstance;
        de = fixture.debugElement;
    });
});

这是可行的。

然而,对于ngrx/store,它不是这样的(如果您用Store in代替TypeaheadService)。我认为您必须编写一个扩展Store的模拟类,然后将其提供给正在测试的组件,但我不确定为什么会这样(如果是这样的话)。

我只是困惑于如何在我的单元测试中模拟ngrx/store,并且在他们的网站或github上找不到任何文档。也许我疏忽了。

EN

回答 3

Stack Overflow用户

发布于 2016-11-30 19:23:24

感谢您发布这个问题并提出了一个潜在的解决方案!

我模拟它的方式是,在每次测试之前使用实际操作来设置初始状态,即模拟状态。下面是一个例子

代码语言:javascript
复制
beforeEach(inject([Store], (store: Store<ApplicationState>) => {
const someFakeState = {
    counter: 9,
    counterFilter: 'A_FAKE_COUNTER_FILTER'
};

store.dispatch(new myActionToSetSomeData(someFakeState));
}));

在您的it()块中,您现在应该能够检查组件是否显示计数为9并按'A_FAKE_COUNTER_FILTER'进行过滤。

当然,您可以在it块中设置状态,而不是beforeEach,只要它在组件被实例化之前。

票数 8
EN

Stack Overflow用户

发布于 2017-09-20 23:52:15

您可以使用forRoot (>= v4)或provideStore ( <= v3)将数据提供给StoreModule,剩下的工作将为您完成:

1-导入:

代码语言:javascript
复制
import { StoreModule } from '@ngrx/store';

2-创建模拟数据:

代码语言:javascript
复制
/*
* Mock data
*/
const PAINTS = [];

3-在您的测试中导入:

代码语言:javascript
复制
beforeEach(async(() => {
  TestBed.configureTestingModule({
    imports: [ StoreModule.forRoot(PAINTS) ]
  })
}))

在以前的版本中(在v4之前),您应该使用provideStore(PAINTS)而不是forRoot(PAINTS)。请参阅changelog here

票数 6
EN

Stack Overflow用户

发布于 2016-11-29 13:35:17

是的,你必须模仿ngrx/store,但不仅仅是商店。Store需要三个参数;一个是Observable类型,另两个是Observable类型,这是一个接口。因此,我尝试了两种方法。将空值传递给StoreMock super()构造函数,但在我的断言中失败。我的另一个解决方案是使用模拟类(在本例中为Observable)实现观察者接口。这样,我就可以将定义的值传递给超级StoreMock构造函数。

这只是一个说明性的例子。ObservableMock实际上并不模拟我试图在应用程序中测试的任何功能。它起到了启动器的作用,这样Store就可以作为提供者注入到我正在测试的组件中。

由于观察者是一个接口,您必须在模拟中实现它的函数声明:nexterrorcomplete

代码语言:javascript
复制
class ObservableMock implements Observer<any> {
  closed?: boolean = false; // inherited from Observer
  nextVal: any = ''; // variable I made up

  constructor() {}

  next = (value: any): void => { this.nextVal = value; };
  error = (err: any): void => { console.error(err); };
  complete = (): void => { this.closed = true; }
}

let actionReducer$: ObservableMock = new ObservableMock();
let action$: ObservableMock = new ObservableMock();
let obs$: Observable<any> = new Observable<any>();

class StoreMock extends Store<any> {
  constructor() {
    super(action$, actionReducer$, obs$);
  }
}

现在您可以将Store作为提供程序添加到组件的测试模块中。

代码语言:javascript
复制
describe('Component:Typeahead', () => {
    beforeEach(() => {
        TestBed.configureTestingModule({
            imports: [...],
            declarations: [Typeahead],
            providers: [
                {provide: Store, useClass: StoreMock} // NOTICE useClass instead of useValue
            ]
        }).compileComponents();
    });
});

我相信还有其他方法可以做到这一点。因此,如果任何人有任何其他答案,请张贴他们!

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40857864

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档