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

Angular测试报No provider for ActivatedRoute及title读取错误如何解决

Angular单元测试报错原因及解决方案

错误原因

  • 错误1:NullInjectorError: No provider for ActivatedRoute!
    LoginComponent构造函数中注入了ActivatedRoute、Router、AuthService、ToastMessageService多个依赖,但测试配置的TestBed中没有提供这些依赖的对应实例,Angular测试运行时找不到提供器就会抛出该注入错误。
  • 错误2:TypeError: Cannot read properties of undefined (reading 'title')
    测试用例中写了断言expect(component.title).toEqual('login page'),但查看组件代码,title是一个无返回值的空方法,并非值为'login page'的字符串属性,类型不匹配导致报错。

解决方案

步骤1:完善测试模块的依赖配置

需要在TestBed中导入路由测试模块,同时mock所有业务服务依赖,避免后续再出现其他注入错误。

步骤2:修复title相关逻辑

如果确实需要title属性断言,将组件中的title() {}修改为title = 'login page';如果不需要该测试,直接删除对应测试用例即可。

步骤3:修正逻辑错误的测试用例

现有测试用例中expect(component.submitted).toBeTruthy()也会执行失败,组件中submitted初始值为false,只有调用onSubmit方法后才会变为true,可根据实际需求调整该用例逻辑。


修正后的完整login.component.spec.ts代码

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { LoginComponent } from './login.component';
import { DebugElement } from '@angular/core';
import { CommonModule } from '@angular/common';
import { BrowserModule, By } from '@angular/platform-browser';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { CoreModule } from '../../core/core.module';
// 导入路由测试模块
import { RouterTestingModule } from '@angular/router/testing';
// 导入需要mock的服务
import { AuthService } from '../../core/services/auth.service';
import { ToastMessageService } from '../../shared/services/toast-message.service';

describe('LoginComponent', () => {
  let component: LoginComponent;
  let fixture: ComponentFixture<LoginComponent>;
  let de: DebugElement;
  let el: HTMLElement;

  // 模拟服务
  const mockAuthService = jasmine.createSpyObj('AuthService', ['login', 'forgotPassword'], {
    currentUserValue: null
  });
  const mockToastService = jasmine.createSpyObj('ToastMessageService', ['setToastMessage']);

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [LoginComponent],
      imports: [
        CommonModule,
        BrowserModule,
        FormsModule,
        CoreModule,
        ReactiveFormsModule,
        // 添加路由测试模块,自动提供ActivatedRoute和Router
        RouterTestingModule
      ],
      // 提供所有依赖的mock实例
      providers: [
        { provide: AuthService, useValue: mockAuthService },
        { provide: ToastMessageService, useValue: mockToastService }
      ]
    })
    .compileComponents()
    .then(() => {
      fixture = TestBed.createComponent(LoginComponent);
      de = fixture.debugElement.query(By.css('form'));
      el = de.nativeElement;
    });
  });

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

  // 如果你修改了组件中的title为字符串属性,保留该用例,否则删除
  fit(`should have as text 'login page'`, () => {
    expect(component.title).toEqual('login page');
  });

  // 修正submitted的断言逻辑,示例改为调用onSubmit后判断
  fit('should set submitted to true after form submit', () => {
    component.onSubmit();
    expect(component.submitted).toBeTruthy();
  });

  fit('should call the onSubmit method', () => {
    fixture.detectChanges();
    spyOn(component, 'onSubmit');
    el = fixture.debugElement.query(By.css('button')).nativeElement;
    el.click();
    expect(component.onSubmit).toHaveBeenCalledTimes(1);
  });

  fit('form should be invalid', () => {
    component.loginForm.controls['email'].setValue('');
    component.loginForm.controls['password'].setValue('');
    expect(component.loginForm.valid).toBeFalsy();
  });

  fit('form should be valid', () => {
    component.loginForm.controls['email'].setValue('asd@asd.com');
    component.loginForm.controls['password'].setValue('aAAada');
    expect(component.loginForm.valid).toBeTruthy();
  });
});

可选组件调整(如果保留title测试用例)

将login.component.ts中的title() {}替换为:

title = 'login page';

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 16:06:00