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

Jest测试报错:无法解析LoginService的全部参数

Angular Jest单元测试:LoginService依赖注入解析失败问题

报错信息

Error: Can't resolve all parameters for LoginService: (?).

at syntaxError (/Users/wilson.gonzalez/Desktop/proyecto_andes/external/npm/node_modules/tslib/tslib.es6.js:170:49)
at CompileMetadataResolver._getDependenciesMetadata (/Users/wilson.gonzalez/Desktop/proyecto_andes/packages/compiler/src/identifiers.ts:69:99)
at CompileMetadataResolver._getTypeMetadata (/Users/wilson.gonzalez/Desktop/proyecto_andes/packages/compiler/src/identifiers.ts:66:95)
at CompileMetadataResolver._getInjectableTypeMetadata (/Users/wilson.gonzalez/Desktop/proyecto_andes/packages/compiler/src/identifiers.ts:69:99)
at CompileMetadataResolver.getProviderMetadata (/Users/wilson.gonzalez/Desktop/proyecto_andes/packages/compiler/src/identifiers.ts:69:99)
at /Users/wilson.gonzalez/Desktop/proyecto_andes/packages/compiler/src/identifiers.ts:69:99
at Array.forEach (<anonymous>)
at CompileMetadataResolver._getProvidersMetadata (/Users/wilson.gonzalez/Desktop/proyecto_andes/packages/compiler/src/identifiers.ts:69:99)
at CompileMetadataResolver.getNgModuleMetadata (/Users/wilson.gonzalez/Desktop/proyecto_andes/packages/compiler/src/identifiers.ts:62:21)
at JitCompiler._loadModules (/Users/wilson.gonzalez/Desktop/proyecto_andes/packages/compiler/src/compile_metadata.ts:482:40)
at JitCompiler._compileModuleAndAllComponents (/Users/wilson.gonzalez/Desktop/proyecto_andes/packages/compiler/src/compile_metadata.ts:482:40)
at JitCompiler.compileModuleAndAllComponentsAsync (/Users/wilson.gonzalez/Desktop/proyecto_andes/packages/compiler/src/compile_metadata.ts:482:40)
at CompilerImpl.compileModuleAndAllComponentsAsync (/Users/wilson.gonzalez/Desktop/proyecto_andes/Andes---ProyectoWeb/node_modules/@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js:615:29)
at TestingCompilerImpl.compileModuleAndAllComponentsAsync (/Users/wilson.gonzalez/Desktop/proyecto_andes/Andes---ProyectoWeb/node_modules/@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js:583:29)
at TestBedViewEngine.compileComponents (/Users/wilson.gonzalez/Desktop/proyecto_andes/Andes---ProyectoWeb/node_modules/@angular/core/bundles/core-testing.umd.js:3360:29)
at Function.TestBedViewEngine.compileComponents (/Users/wilson.gonzalez/Desktop/proyecto_andes/Andes---ProyectoWeb/node_modules/@angular/core/bundles/core-testing.umd.js:3167:27)
at /Users/wilson.gonzalez/Desktop/proyecto_andes/Andes---ProyectoWeb/src/app/views/auth/login/login.component.spec.ts:44:8
at ZoneDelegate.invoke (/Users/wilson.gonzalez/Desktop/proyecto_andes/Andes---ProyectoWeb/node_modules/zone.js/dist/zone.js:457:160)
at ProxyZoneSpec.onInvoke (/Users/wilson.gonzalez/Desktop/proyecto_andes/Andes---ProyectoWeb/node_modules/zone.js/dist/proxy.js:150:35)
at ZoneDelegate.invoke (/Users/wilson.gonzalez/Desktop/proyecto_andes/Andes---ProyectoWeb/node_modules/zone.js/dist/zone.js:457:48)
at Zone.run (/Users/wilson.gonzalez/Desktop/proyecto_andes/Andes---ProyectoWeb/node_modules/zone.js/dist/zone.js:183:37)
at Object.<anonymous> (/Users/wilson.gonzalez/Desktop/proyecto_andes/Andes---ProyectoWeb/node_modules/jest-preset-angular/zone-patch/index.js:51:54)
at Object.asyncJestLifecycle (/Users/wilson.gonzalez/Desktop/proyecto_andes/Andes---ProyectoWeb/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:53:37)
at /Users/wilson.gonzalez/Desktop/proyecto_andes/Andes---ProyectoWeb/node_modules/jest-jasmine2/build/queueRunner.js:45:12
at new Promise (<anonymous>)
at mapper (/Users/wilson.gonzalez/Desktop/proyecto_andes/Andes---ProyectoWeb/node_modules/jest-jasmine2/build/queueRunner.js:28:19)
at /Users/wilson.gonzalez/Desktop/proyecto_andes/Andes---ProyectoWeb/node_modules/jest-jasmine2/build/queueRunner.js:75:41
at processTicksAndRejections (internal/process/task_queues.js:95:5)

排查情况

移除LoginComponent构造函数中的LoginService、Router等依赖注入参数后,测试可正常执行。

测试代码

import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {LoginComponent} from './login.component';
import {LoginService} from '../../../services/login.service';
import {RouterTestingModule} from '@angular/router/testing';
import {UtilitiesService} from '../../../services/utilities.service';
import {Router} from '@angular/router';
import {HttpClient, HttpClientModule} from '@angular/common/http';
import {of} from 'rxjs';
import {CommunicatorService} from '../../../services/communicator.service';
import {LoadingService} from '../../../services/loading.service';
import {ToastrService} from 'ngx-toastr';
import {FormsModule} from '@angular/forms';

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

  beforeEach((() => {
    TestBed.configureTestingModule({
      imports: [RouterTestingModule, HttpClientModule, FormsModule],
      declarations: [
        LoginComponent
      ],
      providers: [
        HttpClient,
        LoadingService,
        UtilitiesService,
        ToastrService,
        {
          provide: Router,
          useValue: {
            navigate: jasmine.createSpy('navigate'),
          },
        },
        {
          provide: CommunicatorService,
          useValue: {
            http_post() { return of({}); },
          },
        },
        LoginService,
      ]
    })
      .compileComponents();
  }));

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

  it('Create', () => {
    expect(component).toBeTruthy();
  });
});

组件代码(依赖注入完整版本)

import {Component, Input, OnInit} from '@angular/core';
import {LoginService} from '../../../services/login.service';
import {Router} from '@angular/router';
import {UtilitiesService} from '../../../services/utilities.service';
import {ToastrService} from 'ngx-toastr';


@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
})
export class LoginComponent implements OnInit {
  constructor(private loginService: LoginService, private router: Router, private utilitiesService:UtilitiesService, private toastr: ToastrService) {}
  private _email = '';
  private _password = '';
  private _isChecked = false;
  private _disable=false;

  ngOnInit(): void {
    this.checkIsSaveUser();
  }

  checkIsSaveUser() {
    const emailSaved = localStorage.getItem('USER_ACTIVE');
    if(emailSaved !== undefined && emailSaved !== 'null' && emailSaved !== ''){
       this._email = emailSaved;
       this._isChecked = true;
    }
  }
  checkInfo(){
    return !this.utilitiesService.validatorsFields(this._email) ||
      !this.utilitiesService.validatorsFields(this._password)|| !this.utilitiesService.validatorsEmail(this._email);
  }
  saveUser() {
    if(!this._isChecked)  {
      this._isChecked = true;
      localStorage.setItem('USER_ACTIVE', this._email);
    } else   {
      this._isChecked = false;
      localStorage.setItem('USER_ACTIVE', '');
    }
  }

  login(){
    this.loginService.user = this._email;
    this.loginService.password = this._password;
    if(this._isChecked)  {
      localStorage.setItem('USER_ACTIVE', this._email);
    }
    this.loginService.login().subscribe(result => {
      this.loginService.tokenSecret = result.data.token;
      this.loginService.rol = result.data.rol;
      this.router.navigate(['admin/tables']);
    }, error => {
      this.toastr.error(error.error.code +': ' +  error.error.message, 'Error', {
        timeOut: 7000,
      });
    })
  }


  get password(): string {
    return this._password;
  }

  set password(value: string) {
    this._password = value;
  }

  get isChecked(): boolean {
    return this._isChecked;
  }

  set isChecked(value: boolean) {
    this._isChecked = value;
  }

  get disable(): boolean {
    return this._disable;
  }

  set disable(value: boolean) {
    this._disable = value;
  }

  get email(): string {
    return this._email;
  }

  set email(value: string) {
    this._email = value;
  }
}

解决方案

1. 模拟LoginService(推荐)

单元测试应隔离真实服务的依赖,将测试模块中LoginService的直接注册替换为模拟实现:

{
  provide: LoginService,
  useValue: {
    user: '',
    password: '',
    tokenSecret: '',
    rol: '',
    login: () => of({ data: { token: 'mock-token', rol: 'admin' } })
  }
}

这样完全避免了真实LoginService的依赖解析问题,同时能控制其行为。

2. 检查LoginService的依赖

如果必须使用真实LoginService,需确认其构造函数的所有参数都已在测试模块中提供。比如LoginService若依赖CommunicatorService,需确保测试中提供的模拟符合其调用要求。

3. 验证TypeScript配置

确保tsconfig.json中启用了装饰器元数据生成,否则Angular无法解析依赖参数:

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 08:42:40