You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 12:15:31