Angular 5项目中Apollo单元测试的依赖注入问题排查
我来帮你搞定这个测试里的Apollo报错问题,咱们一步步拆解:
先说说你遇到的两个错误原因
第一个错误:
NullInjectorError: No provider for Apollo!
这个错误逻辑很明确——你的测试模块里没有为Apollo服务提供依赖注入的提供者。declarations数组是用来声明组件、指令、管道的,服务根本不属于这个范畴,所以你一开始没加提供者才会找不到Apollo实例。第二个错误:
Failed: Unexpected value 'Apollo' declared by the module 'DynamicTestModule'
你把Apollo放进declarations里就踩坑了!Apollo是用@Injectable()装饰的服务,不是@Component/@Directive/@Pipe装饰的类型,Angular模块只会把后者当作declarations的合法成员,所以才会抛出这个异常。
正确的解决方法:Mock Apollo服务(推荐)
单元测试的核心是隔离组件的外部依赖,所以最好的方式是Mock掉Apollo服务,而不是引入真实的GraphQLModule(避免发起真实请求或依赖外部配置)。这里用Jasmine的createSpyObj就能快速创建Mock实例:
beforeEach(async(() => { // 创建Mock的Apollo服务,模拟你组件用到的方法(比如watchQuery) const mockApollo = jasmine.createSpyObj('Apollo', ['watchQuery']); // 模拟watchQuery的返回值,匹配组件里的调用逻辑 mockApollo.watchQuery.and.returnValue({ valueChanges: of({ data: { /* 这里放你需要模拟的GraphQL返回数据 */ } }) }); TestBed.configureTestingModule({ declarations: [ContractsDashboardComponent], providers: [ // 告诉Angular,当组件请求Apollo时,用我们的Mock实例 { provide: Apollo, useValue: mockApollo } ] }).compileComponents(); }));
关于GraphQLModule的处理
你的正式项目里有GraphQLModule,它的构造函数会调用apollo.create——但在单元测试里,不建议直接导入这个模块,因为它会初始化真实的Apollo客户端,可能会连接到真实后端,这违背了单元测试隔离依赖的原则。
如果多个测试都需要用到Apollo的Mock,你也可以封装一个MockGraphQLModule,在里面统一提供Mock的Apollo服务,然后在测试模块里导入这个Mock模块即可,这样能复用配置。
内容的提问来源于stack exchange,提问作者MonkeyBonkey

