Angular 4组件内直接调用http.get的测试方法咨询
搞定Angular 4组件HTTP调用的测试问题
嘿,我来帮你解决这个测试的问题!首先提个小细节:你组件里的crispList其实是个Observable,不是直接的数组数据——因为你把http.get经过map处理后的Observable直接赋值给它了。这意味着测试时我们得订阅它才能拿到实际值来做断言。
接下来咱们一步步完善你的测试代码,同时搞定两个测试目标:验证HTTP调用确实执行了,以及crispList的值和模拟数据一致。
核心思路梳理
我们已经用了MockBackend来模拟HTTP请求,接下来要做的就是:
- 在Mock的连接回调里标记请求是否触发,同时验证请求URL正确
- 订阅
crispList这个Observable,在回调里断言数据是否符合预期
修改后的完整测试代码
describe('CrispFlavourComponent', () => { let backend: MockBackend; let componentFixture: ComponentFixture<CrispFlavourComponent>; let component: CrispFlavourComponent; const mockResponse = { walkers: { crisps: [ { name: 'Salt & Vinegar' }, { name: 'Cheese & Onion' } ] } }; let isHttpCalled = false; // 用来标记HTTP请求是否被触发 beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ RouterTestingModule.withRoutes([ { path: '**', component: DummyComponent } ]), TranslateI18NextTestingModule.forRoot() ], declarations: [ DummyComponent, CrispFlavorComponent ], schemas: [CUSTOM_ELEMENTS_SCHEMA], providers: [ MockBackend, BaseRequestOptions, { provide: Http, useFactory: (backendInstance: MockBackend, defaultOptions: BaseRequestOptions) => { return new Http(backendInstance, defaultOptions); }, deps: [MockBackend, BaseRequestOptions] } ] }); TestBed.compileComponents().then(() => { componentFixture = TestBed.createComponent(CrispFlavourComponent); component = componentFixture.componentInstance; // 提前拿到组件实例,方便后续操作 }); })); beforeEach(inject([MockBackend], (mockBackend: MockBackend) => { backend = mockBackend; isHttpCalled = false; // 每次测试前重置标记 backend.connections.subscribe((connection: MockConnection) => { // 验证请求的URL是不是我们要的那个 expect(connection.request.url).toBe('path/to/crisp-flavors.json'); isHttpCalled = true; // 标记请求已触发 // 返回模拟的响应数据 const options = new ResponseOptions({ status: 200, body: JSON.stringify(mockResponse) }); connection.mockRespond(new Response(options)); }); })); it('should load crisp flavors and verify HTTP call is made', (done) => { component.ngOnInit(); // 订阅crispList,拿到数据后做断言 component.crispList.subscribe((crisps) => { // 验证返回的列表和我们的模拟数据一致 expect(crisps).toEqual(mockResponse.walkers.crisps); // 验证HTTP请求确实被执行了 expect(isHttpCalled).toBe(true); done(); // 告诉Jasmine异步测试完成,不用再等啦 }); }); });
关键改动说明
- 提前获取组件实例:把
component实例提前拿到,这样调用ngOnInit和访问crispList都更方便。 - HTTP请求标记:用
isHttpCalled变量记录请求是否触发,再结合URL验证,确保调用的是正确的接口。 - 异步测试处理:因为HTTP请求是异步的,所以要用
done回调告诉Jasmine等我们的订阅回调执行完再结束测试,不然测试会提前跑完,断言根本没执行。 - 数据断言:在订阅的回调里直接对比返回的
crisps和模拟数据,确保我们的map处理逻辑是对的。
额外小建议:如果想让crispList是实际数组
如果你希望组件里的crispList是直接的数组(不是Observable),可以修改组件代码,在ngOnInit里订阅HTTP请求并赋值:
public crispList: any[] = []; // 改成数组类型 public ngOnInit() { this.http.get('path/to/crisp-flavors.json').map((res: any) => { const respJson = res.json(); return respJson.walkers.crisps; }).subscribe((crisps) => { this.crispList = crisps; }); }
这种情况下,测试可以用fixture.whenStable()来等待异步操作完成:
it('should load the list of Crisp Flavors', async(() => { component.ngOnInit(); componentFixture.whenStable().then(() => { expect(component.crispList).toEqual(mockResponse.walkers.crisps); expect(isHttpCalled).toBe(true); }); }));
这样就能完美满足你的两个测试需求啦!
内容的提问来源于stack exchange,提问作者Mark Sandman
相关产品推荐
相关产品推荐

