Angular单元测试组件注入CookieService时的报错问题排查
问题根因
报错来自两处写法错误:
- 最初的mock配置里,
{provide: CookieService, useValue: get('name')}传入的是get函数执行后的字符串返回值,不是带get方法的服务对象,组件调用this.cookieService.get()时自然找不到对应方法。 - 测试用例里手动写
new HelloWorldComponent(FormBuilder,CookieService)完全绕过了Angular TestBed的依赖注入体系,传进去的是服务类本身,不是TestBed里配置好的mock服务实例,之前写的依赖配置根本没生效。
可行解决方案
你可以任选以下两种方式实现正确mock:
方案1:使用jasmine spy对象快速mock(无需额外写桩类)
直接用jasmine.createSpyObj创建带指定方法的mock服务,配置到TestBed的providers中,不要手动new组件,通过TestBed获取注入后的组件实例:
import { CookieService } from "ngx-cookie-service"; import { FormBuilder } from "@angular/forms"; import { HelloWorldComponent } from "./helloworld.component"; import { TestBed, ComponentFixture } from "@angular/core/testing"; describe('HelloWorldComponent', () => { let component: HelloWorldComponent; let fixture: ComponentFixture<HelloWorldComponent>; // 声明mock服务 const mockedFormBuilder = jasmine.createSpyObj('FormBuilder', ['control', 'array', 'group']); // 把组件中会用到的CookieService方法都写到第二个数组参数里 const mockedCookieService = jasmine.createSpyObj('CookieService', ['get', 'set', 'delete', 'check']); beforeEach(async(() => { // 配置mock方法的返回值 mockedCookieService.get.and.returnValue('test-cookie-value'); TestBed.configureTestingModule({ declarations: [HelloWorldComponent], providers: [ { provide: FormBuilder, useValue: mockedFormBuilder }, { provide: CookieService, useValue: mockedCookieService } ] }).compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(HelloWorldComponent); component = fixture.componentInstance; fixture.detectChanges(); }); it('should create component correctly', () => { expect(component).toBeTruthy(); // 验证get方法是否被正确调用 expect(mockedCookieService.get).toHaveBeenCalledWith('somename'); }); it('getTextArray should return split email array', () => { const text = 'text@domain.com'; const textArr = ['text@domain.com']; const getArr = component.getTextArray(text); expect(getArr).toEqual(textArr); }); });
方案2:使用自定义桩服务(Stub)
你之前写的CookieServiceStub桩类本身逻辑没问题,只需要修正组件实例化的方式,走TestBed的依赖注入即可:
// 桩类定义 export class CookieServiceStub { cookie: string = 'gdhjgsfgsjdfg'; get(name: string): string { return this.cookie; } // 组件里用到其他CookieService方法也需要在这里补充实现 }
TestBed配置保持你之前的useClass写法即可,同样通过TestBed.createComponent获取组件实例,不要手动new。
注意事项
- 所有Angular组件、服务的单元测试,只要用了TestBed配置依赖,就不要手动用
new关键字实例化类,否则TestBed配置的依赖注入规则完全不生效。 - mock服务时只需要实现组件中实际调用到的方法即可,不需要把第三方服务的所有方法都完整实现。
内容的提问来源于stack exchange,提问作者Hiraja
相关产品推荐
相关产品推荐

