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

如何编写Angular AuthService单元测试并解决超时等相关问题

AuthService单元测试问题解决与完整测试指南

一、超时错误的原因与修复

你的测试超时是两个核心问题导致的:

  1. 使用done回调但未在subscribe回调内调用done(),Jasmine始终等待异步完成信号;
  2. mokcReq.flush传递的是messageResponse.message(字符串),但服务的register方法期望返回MessageResponse对象,导致subscribe内的断言逻辑未正确触发,进一步卡住测试流程。

修复后的register测试代码:

it('should register user successfully', (done) => {
  const body: RegisterData = {
    email: 'test1@mail.com',
    firstName: 'test',
    lastName: 'test',
    password: '12345678',
  };

  const messageResponse: MessageResponse = {
    message: 'User registered successfully',
  };

  service.register(body).subscribe((response) => {
    expect(response).toEqual(messageResponse); // 更精准的对象断言
    done(); // 必须调用done通知Jasmine异步流程结束
  });

  const mockReq = testingController.expectOne(
    `${environment.apiURL}/${EndPoints.auth}/${EndPoints.register}`
  );
  expect(mockReq.request.method).toBe('POST'); // 额外断言请求方法正确性
  mockReq.flush(messageResponse); // 传递完整的响应对象,而非字符串
  testingController.verify();
});

二、关于数据库操作的疑问

完全不用担心测试会在真实数据库创建用户:

  • 你使用的HttpClientTestingModule会拦截所有HTTP请求,不会向真实后端发送请求,所有请求都是在内存中模拟完成的;
  • 测试里的flush只是模拟后端返回的响应数据,不会触发任何真实的数据库写入操作。

三、其他方法的测试示例

1. login方法测试

it('should login user successfully', (done) => {
  const body: LoginData = {
    email: 'test@mail.com',
    password: '12345678',
  };
  const mockUser: ResponseUser = {
    id: 1,
    email: 'test@mail.com',
    firstName: 'test',
    lastName: 'test',
  };

  service.login(body).subscribe((user) => {
    expect(user).toEqual(mockUser);
    done();
  });

  const mockReq = testingController.expectOne(
    `${environment.apiURL}/${EndPoints.auth}/${EndPoints.login}`
  );
  expect(mockReq.request.method).toBe('POST');
  expect(mockReq.request.withCredentials).toBe(true); // 断言请求的withCredentials配置
  mockReq.flush(mockUser);
  testingController.verify();
});

2. logout方法测试

it('should logout user successfully', (done) => {
  const mockResponse: MessageResponse = {
    message: 'Logged out successfully',
  };

  service.logout().subscribe((response) => {
    expect(response).toEqual(mockResponse);
    done();
  });

  const mockReq = testingController.expectOne(
    `${environment.apiURL}/${EndPoints.auth}/${EndPoints.logout}`
  );
  expect(mockReq.request.method).toBe('GET');
  expect(mockReq.request.withCredentials).toBe(true);
  mockReq.flush(mockResponse);
  testingController.verify();
});

3. autoLogin方法测试

it('should auto-login user successfully', (done) => {
  const mockUser: ResponseUser = {
    id: 1,
    email: 'test@mail.com',
    firstName: 'test',
    lastName: 'test',
  };

  service.autoLogin().subscribe((user) => {
    expect(user).toEqual(mockUser);
    done();
  });

  const mockReq = testingController.expectOne(
    `${environment.apiURL}/${EndPoints.auth}/${EndPoints.autoLogin}`
  );
  expect(mockReq.request.method).toBe('GET');
  expect(mockReq.request.withCredentials).toBe(true);
  mockReq.flush(mockUser);
  testingController.verify();
});

4. loggedUser$(NgRx Store)测试

需要模拟NgRx Store的状态返回,使用provideMockStore工具:

import { provideMockStore, MockStore } from '@ngrx/store/testing';
import { selectIsUserLogged } from './path-to-your-selectors'; // 替换为你的实际选择器路径

// 修改beforeEach中的TestBed配置
beforeEach(() => {
  TestBed.configureTestingModule({
    imports: [HttpClientTestingModule],
    providers: [
      AuthService,
      provideMockStore({
        initialState: {},
        selectors: [
          { selector: selectIsUserLogged, value: false }, // 初始模拟未登录状态
        ],
      }),
    ],
  });
  service = TestBed.inject(AuthService);
  testingController = TestBed.inject(HttpTestingController);
  const store: MockStore = TestBed.inject(MockStore);
});

it('should emit correct logged state from store', (done) => {
  // 模拟store返回已登录状态
  store.overrideSelector(selectIsUserLogged, true);
  store.refreshState(); // 通知订阅者状态更新

  service.loggedUser$.subscribe((isLogged) => {
    expect(isLogged).toBe(true);
    done();
  });
});

内容的提问来源于stack exchange,提问作者Michał

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 13:10:03