Angular Jasmine单元测试:如何Mock组件调用服务内的HTTP请求返回结果
Angular Karma/Jasmine 单元测试实现方案
你不需要在组件单元测试中模拟服务内部的HTTP请求,因为你已经通过spy替换了RandomService的getRandomItems对外方法,直接控制该方法的返回值即可完成组件逻辑验证。如果需要单独验证服务内部的HTTP处理逻辑,再使用Angular提供的HttpClientTestingModule模拟HTTP请求即可。
组件单元测试实现(验证getPlans方法逻辑)
直接构造符合你预期顺序的RandomItem数组,作为spy的返回值即可:
import { of, throwError } from 'rxjs'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { PlansComponent } from './plans.component'; import { RandomService } from './random.service'; // 其他类型导入省略 describe('PlansComponent', () => { let component: PlansComponent; let fixture: ComponentFixture<PlansComponent>; let randomSpy: jasmine.SpyObj<RandomService>; beforeEach(async () => { // 初始化服务Spy const spy = jasmine.createSpyObj('RandomService', ['getRandomItems']); await TestBed.configureTestingModule({ declarations: [PlansComponent], providers: [ { provide: RandomService, useValue: spy } ] }).compileComponents(); randomSpy = TestBed.inject(RandomService) as jasmine.SpyObj<RandomService>; }); it('getPlans执行后应该正确拆分活跃/非活跃条目,且顺序符合预期', () => { // 按照服务调整后的返回顺序构造模拟数据 const mockItems: RandomItem[] = [ { id: 'active_1', isActive: true, name: '活跃条目1' }, { id: 'active_2', isActive: true, name: '活跃条目2' }, { id: 'pending_1', isActive: false, name: '待处理条目1' }, { id: 'pending_2', isActive: false, name: '待处理条目2' } ]; // 设置Spy返回模拟数据 randomSpy.getRandomItems.and.returnValue(of(mockItems)); // 初始化组件,触发构造函数内的getPlans调用 fixture = TestBed.createComponent(PlansComponent); component = fixture.componentInstance; fixture.detectChanges(); // 断言结果符合预期 expect(randomSpy.getRandomItems).toHaveBeenCalledWith(component.id); expect(component.activeItems.length).toBe(2); expect(component.activeItems[0].id).toBe('active_1'); // 验证顺序 expect(component.randomItems.length).toBe(2); expect(component.randomItems[0].id).toBe('pending_1'); expect(component.loading).toBeFalse(); }); it('getPlans请求失败时应该触发错误处理', () => { const mockError: ResponseError = { code: 500, message: '请求异常' }; randomSpy.getRandomItems.and.returnValue(throwError(() => mockError)); // 监听错误处理方法 spyOn(component, 'handleError'); fixture = TestBed.createComponent(PlansComponent); component = fixture.componentInstance; fixture.detectChanges(); expect(component.handleError).toHaveBeenCalledWith(mockError); expect(component.loading).toBeFalse(); }); });
服务单元测试实现(验证内部HTTP请求处理逻辑)
如果需要单独验证RandomService中getRandomItems方法对接口返回值的拼接逻辑,使用HttpClientTestingModule模拟HTTP请求:
import { TestBed } from '@angular/core/testing'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { RandomService } from './random.service'; describe('RandomService', () => { let service: RandomService; let httpTestingController: HttpTestingController; beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule], providers: [RandomService] }); service = TestBed.inject(RandomService); httpTestingController = TestBed.inject(HttpTestingController); }); it('getRandomItems应该正确拼接活跃条目和待处理条目返回', () => { const testId = 'test_id_123'; // 模拟接口原始返回值 const mockApiRes = { activeItem: [ { id: 'a1', isActive: true }, { id: 'a2', isActive: true } ], pendingItem: [ { id: 'p1', isActive: false }, { id: 'p2', isActive: false } ] }; service.getRandomItems(testId).subscribe(result => { // 断言返回数组顺序为活跃条目在前,待处理条目在后 expect(result.length).toBe(4); expect(result[0].id).toBe('a1'); expect(result[2].id).toBe('p1'); }); // 验证请求地址、方法符合预期 const req = httpTestingController.expectOne(`/items/${testId}/getRandomItems`); expect(req.request.method).toBe('GET'); // 注入模拟接口返回值 req.flush(mockApiRes); // 验证无多余请求 httpTestingController.verify(); }); });
内容的提问来源于stack exchange,提问作者software_dude5050
相关产品推荐
相关产品推荐

