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

Angular单元测试报错:spyOn找不到login()对象,咨询TestBed问题

Understanding TestBed & Fixing the <spyOn>: could not find an object to spy upon for login() Error

First, let's confirm your understanding of TestBed: You're mostly right! Angular's TestBed acts as a testing module builder that sets up a mini Angular environment tailored for your tests. It handles creating component instances, injecting dependencies (like services), configuring necessary imports (such as FormsModule or RouterTestingModule), and initializing component views. However, a key nuance is that it doesn't automatically detect all dependencies—you have to explicitly tell it which components, services, and modules your test needs via configureTestingModule.

Now, let's tackle that <spyOn> error. This issue almost always stems from one of three common mistakes:

Common Causes & Fixes

1. The service isn't properly provided in your TestBed configuration

If your LoginComponent depends on an AuthService (or similar) with the login() method, you need to include this service in the providers array of your TestBed setup. Without this, TestBed can't inject the service into your component, so there's no instance to spy on.

2. You're spying on the service class instead of an injected instance

spyOn requires an existing object instance to work. Trying to spy on the service class directly (e.g., spyOn(AuthService, 'login')) will fail because you're targeting the class, not an instantiated object. You need to get the injected service instance first.

3. The login() method isn't a public instance method

If login() is a private method or a static method on the service, spyOn won't be able to target it. For unit testing, service methods you want to mock/spy on should be public instance methods.

Example Correct Setup

Here's a complete example of how to configure TestBed and properly spy on the login() method:

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { LoginComponent } from './login.component';
import { AuthService } from '../services/auth.service';
import { FormsModule } from '@angular/forms'; // Include if using template-driven forms

describe('LoginComponent', () => {
  let component: LoginComponent;
  let fixture: ComponentFixture<LoginComponent>;
  let authService: AuthService; // Holds the injected service instance

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [LoginComponent], // Declare your component
      imports: [FormsModule], // Add any modules your component uses
      providers: [AuthService] // Provide the service the component depends on
    }).compileComponents();

    // Create component fixture and instance
    fixture = TestBed.createComponent(LoginComponent);
    component = fixture.componentInstance;

    // Get the injected service instance from TestBed
    authService = TestBed.inject(AuthService);

    // Trigger initial change detection
    fixture.detectChanges();
  });

  it('should call AuthService.login() when form is submitted', () => {
    // Spy on the login method of the injected service instance
    const loginSpy = spyOn(authService, 'login').and.returnValue(Promise.resolve(true));

    // Simulate user input
    component.email = 'test@example.com';
    component.password = 'test123';

    // Trigger the submit method
    component.onSubmit();

    // Verify the spy was called with the correct arguments
    expect(loginSpy).toHaveBeenCalledWith('test@example.com', 'test123');
  });
});

For better isolation (so your component tests don't depend on the real service's implementation), you can provide a mock service instead:

// Create a mock AuthService
const mockAuthService = {
  login: jasmine.createSpy('login').and.returnValue(Promise.resolve(true))
};

// In TestBed configuration:
providers: [{ provide: AuthService, useValue: mockAuthService }]

// Then in your test:
expect(mockAuthService.login).toHaveBeenCalledWith(...);

This approach keeps your component tests focused on the component's behavior, not the service's logic.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 12:23:08