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

Angular 4.2.4组件getMotivos方法subscribe逻辑单元测试问题

Angular 4.2.4单元测试:验证subscribe回调后showLoading状态变更

我们使用Angular 4.2.4,需要为组件编写单元测试,目标是测试MotivosCancelamentoComponent中getMotivos方法内的subscribe回调,验证调用该方法后showLoading变量是否变为false,且需要模拟服务返回值。之前尝试多个方案均未成功。

待测试组件代码(motivos-cancelamento.component.ts)

export class MotivosCancelamentoComponent implements OnInit {
  showLoading = true;

  constructor(
    private service: MotivosCancelamentoService,
  ) { }

  ngOnInit() {
    this.getMotivos();
  }

  getMotivos() {
    this.service.getMotivos().subscribe((data) => {
      this.showLoading = false;
    },
    (error: any) => {
      this.redirectError();
    });
  }
}

当前编写的单元测试代码(motivos-cancelamento.component.spec.ts)

describe('MotivosCancelamentoComponent', () => {
  let component: MotivosCancelamentoComponent;
  let service: MotivosCancelamentoService;
  let fixture: ComponentFixture<MotivosCancelamentoComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ MotivosCancelamentoComponent ],
      providers:
      [
        { provide: MotivosCancelamentoService, useValue: motivosCancelamentoServiceStub }
      ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(MotivosCancelamentoComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it("should call getMotivos and return showLoading value as false", async(() => {
    const showLoading = false;
    spyOn(service, 'getMotivos').and.returnValue(showLoading)
    fixture.detectChanges();
    expect(component.showLoading).toEqual(showLoading);
  }));
});

相关服务代码(motivos-cancelamento.service.ts)

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';

export interface Entries {
    entries: any[];
}

const motivos = {
    'entries': [{
        '_version': 1,
    }
    ]
}

@Injectable()
export class MotivosCancelamentoService {

    constructor() { }

    getMotivos(): Observable<object> {
        return of(motivos);
    }

}

export const motivosCancelamentoServiceStub =
{
    getMotivos: ()=> {
        return of(motivos)
    }
}

测试失败原因分析

  1. 服务实例未正确获取:测试中声明了service变量,但未通过TestBed.get获取实例,导致spyOn调用时service为undefined。
  2. 返回值类型错误:getMotivos方法要求返回Observable,但测试中直接返回布尔值,导致subscribe无法执行回调。
  3. 生命周期触发时机错误:fixture.detectChanges()在组件初始化时就触发了ngOnInit,此时spy还未设置,实际调用的是原stub方法,测试逻辑未生效。

修正后的单元测试代码

describe('MotivosCancelamentoComponent', () => {
  let component: MotivosCancelamentoComponent;
  let service: MotivosCancelamentoService;
  let fixture: ComponentFixture<MotivosCancelamentoComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [MotivosCancelamentoComponent],
      providers: [
        { provide: MotivosCancelamentoService, useValue: motivosCancelamentoServiceStub }
      ]
    }).compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(MotivosCancelamentoComponent);
    component = fixture.componentInstance;
    // 先获取服务实例,暂不触发ngOnInit
    service = TestBed.get(MotivosCancelamentoService);
  });

  it('should set showLoading to false after getMotivos succeeds', (done) => {
    // 验证初始状态为true
    expect(component.showLoading).toBe(true);
    
    // 创建模拟Observable并spy服务方法
    const mockData = { entries: [] };
    const mock$ = of(mockData);
    spyOn(service, 'getMotivos').and.returnValue(mock$);
    
    // 调用组件方法
    component.getMotivos();
    
    // 订阅完成后验证状态变更
    mock$.subscribe(() => {
      expect(component.showLoading).toBe(false);
      done(); // 标记异步测试完成
    });
  });

  it('should update showLoading after ngOnInit triggers getMotivos', () => {
    // spy服务方法并保留原stub逻辑
    spyOn(service, 'getMotivos').and.callThrough();
    
    // 触发ngOnInit
    fixture.detectChanges();
    
    // 验证服务方法被调用,且状态变更
    expect(service.getMotivos).toHaveBeenCalled();
    expect(component.showLoading).toBe(false);
  });
});

关键修正说明

  • 获取服务实例:在beforeEach中通过TestBed.get(MotivosCancelamentoService)获取服务实例,确保spy能正确挂载。
  • 控制生命周期触发:延迟调用fixture.detectChanges(),先设置spy再触发ngOnInit或调用组件方法。
  • 返回正确类型:使用of()创建模拟Observable,保证subscribe回调能正常执行。
  • 异步测试处理:针对subscribe的异步特性,使用done()回调通知测试框架异步操作完成,避免测试提前结束。

内容的提问来源于stack exchange,提问作者Oo'-

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 10:31:12