Jasmine Karma测试Ionic/Angular登录函数:伪造HTTP响应关闭Loader
解决Jasmine Karma测试中Loader无法消失的问题
核心问题原因
你当前的测试直接调用component.login(),但没模拟userService.login()的HTTP响应,导致订阅的成功/错误回调根本没执行,自然不会调用loader.dismiss(),Loader就一直显示了。
解决步骤
1. 模拟依赖服务(UserService和LoadingController)
在测试的beforeEach里创建这两个服务的模拟对象,避免实际发起HTTP请求或创建真实Loader:
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { LoadingController, AlertController, Router } from '@angular/common'; import { UserService } from 'path/to/user.service'; import { of, throwError } from 'rxjs'; describe('YourComponent', () => { let component: YourComponent; let fixture: ComponentFixture<YourComponent>; let mockUserService: jasmine.SpyObj<UserService>; let mockLoadingCtrl: jasmine.SpyObj<LoadingController>; let mockAlertCtrl: jasmine.SpyObj<AlertController>; let mockRouter: jasmine.SpyObj<Router>; beforeEach(async () => { // 创建spy模拟对象 mockUserService = jasmine.createSpyObj('UserService', ['login']); mockLoadingCtrl = jasmine.createSpyObj('LoadingController', ['create']); mockAlertCtrl = jasmine.createSpyObj('AlertController', ['show']); mockRouter = jasmine.createSpyObj('Router', ['navigate']); // 模拟Loader实例,包含present和dismiss方法 const mockLoader = jasmine.createSpyObj('Loader', ['present', 'dismiss']); mockLoadingCtrl.create.and.returnValue(Promise.resolve(mockLoader)); await TestBed.configureTestingModule({ declarations: [YourComponent], providers: [ { provide: UserService, useValue: mockUserService }, { provide: LoadingController, useValue: mockLoadingCtrl }, { provide: AlertController, useValue: mockAlertCtrl }, { provide: Router, useValue: mockRouter } ] }).compileComponents(); fixture = TestBed.createComponent(YourComponent); component = fixture.componentInstance; fixture.detectChanges(); });
2. 成功登录的测试用例
让userService.login()返回成功的Observable,触发成功回调并调用loader.dismiss():
it('should dismiss loader and navigate on successful login', async () => { // 模拟登录成功响应 mockUserService.login.and.returnValue(of({ success: true })); await component.login(); // login是async函数,必须加await等待异步操作完成 // 验证Loader的present和dismiss被调用 const mockLoader = await mockLoadingCtrl.create(); expect(mockLoader.present).toHaveBeenCalled(); expect(mockLoader.dismiss).toHaveBeenCalled(); // 验证路由跳转逻辑 expect(mockRouter.navigate).toHaveBeenCalledWith(['/user-home']); });
3. 登录失败的测试用例
模拟请求错误,触发错误回调并验证loader.dismiss()执行:
it('should dismiss loader and show alert on login failure', async () => { // 模拟登录错误 const testError = 'Invalid credentials'; mockUserService.login.and.returnValue(throwError(() => testError)); await component.login(); const mockLoader = await mockLoadingCtrl.create(); expect(mockLoader.present).toHaveBeenCalled(); expect(mockLoader.dismiss).toHaveBeenCalled(); // 验证错误提示框触发 expect(mockAlertCtrl.show).toHaveBeenCalledWith(testError, 'OK'); });
关键注意点
login()是异步函数,测试时必须加await,确保所有异步逻辑执行完再做断言。- 必须模拟
LoadingController.create()返回的Loader实例,否则调用present()和dismiss()会报错。 - 用
of()创建成功Observable,throwError()创建错误Observable,以此模拟HTTP请求的不同结果。
内容的提问来源于stack exchange,提问作者max
相关产品推荐
相关产品推荐

