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

使用Jasmine测试Angular HTTP服务报错:期望为AddUserShareModel,实际为SafeSubscriber

解决Angular Jasmine测试中Observable提取值的错误问题

错误原因

  1. subscribe()方法返回的是SafeSubscriber订阅对象,而非Observable发出的实际数据,你把它赋值给result,自然无法匹配AddUserShareModel类型。
  2. 直接调用服务的HTTP方法会发起真实请求,测试应该模拟后端响应,避免依赖外部服务。

解决方案

使用Angular提供的HttpTestingController模拟HTTP请求,同时用RxJS的firstValueFrom将Observable转换为Promise,配合async/await获取数据。

修改后的完整测试代码

import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { TestBed } from '@angular/core/testing';
import { AddUserShareModel } from 'src/app/shared/models/add.userShare.model';
import { UserShareService } from '../../app/services/userShare.service';
import { firstValueFrom } from 'rxjs';
import { environment } from 'src/environments/environment';

describe('UserShareService', () => {
    let service: UserShareService;
    let httpTestingController: HttpTestingController;
    const mockApiUrl = `${environment.rootUrl}/api/UserShare`;

    beforeEach(() => {
      TestBed.configureTestingModule({
        imports: [HttpClientTestingModule],
        providers: [UserShareService],
      });
      service = TestBed.inject(UserShareService);
      httpTestingController = TestBed.inject(HttpTestingController);
    });

    // 清理未处理的请求,防止测试泄漏
    afterEach(() => {
      httpTestingController.verify();
    });

    it('should be created', () => {
      expect(service).toBeTruthy();
    });

    it("should have defined method addUserShare", () => {
      expect(service.addUserShare).toBeDefined();
    });

    it('should add share and return AddUserShareModel', async () => {
      // 准备测试数据
      const testModel = new AddUserShareModel(20, "reciever@email.de", ["guid1", "guid2"]);
      const mockResponse = new AddUserShareModel(20, "reciever@email.de", ["guid1", "guid2"]);

      // 将Observable转为Promise,用async/await获取结果
      const resultPromise = firstValueFrom(service.addUserShare(testModel));

      // 捕获并验证HTTP请求
      const req = httpTestingController.expectOne(`${mockApiUrl}/Add`);
      expect(req.request.method).toBe('PUT');
      expect(req.request.body).toEqual(testModel);
      // 返回模拟响应
      req.flush(mockResponse);

      // 获取结果并断言
      const result = await resultPromise;
      expect(result).toBeTruthy();
      expect(result).toBeDefined();
      expect(result).toEqual(mockResponse);
    });
});

关键说明

  • HttpTestingController:捕获服务发起的HTTP请求,模拟后端响应,确保测试不依赖真实服务。
  • firstValueFrom:RxJS 7+提供的方法,将Observable转换为Promise,配合async/await优雅处理异步数据(RxJS 6及以下可使用toPromise(),但该方法已废弃)。
  • afterEach中的verify():确保所有发起的HTTP请求都被处理,避免测试残留未完成的请求。
  • expectOne:匹配对应的请求URL,验证服务调用了正确的接口地址。

额外提示

如果需要宽松匹配对象而非严格匹配类实例,可以用jasmine.objectContaining断言属性:

expect(result).toEqual(jasmine.objectContaining({
  daysActive: 20,
  receiverEmail: "reciever@email.de",
  documentIds: ["guid1", "guid2"]
}));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 05:35:11