测试具有抽象类依赖关系的Angular服务时出现问题

测试具有抽象类依赖关系的Angular服务时出现问题,angular,typescript,unit-testing,karma-jasmine,Angular,Typescript,Unit Testing,Karma Jasmine,我有一个服务,它需要依赖于另一个服务,而另一个服务又需要依赖于两个抽象类 (ThemeConfigService -> (SettingsService -> SettingsLoader, NavigationLoader)) 我已经让测试失败了,因为它找不到通过抽象类公开的方法(不是函数异常) 我不知道我怎么才能通过这个考试,网上的各种搜索都没有什么帮助 下面是主题配置服务,我正试图为其充实一个测试“theme-config.service.ts” @可注入({ provide

我有一个服务,它需要依赖于另一个服务,而另一个服务又需要依赖于两个抽象类

(ThemeConfigService -> (SettingsService -> SettingsLoader, NavigationLoader))
我已经让测试失败了,因为它找不到通过抽象类公开的方法(不是函数异常)

我不知道我怎么才能通过这个考试,网上的各种搜索都没有什么帮助

下面是主题配置服务,我正试图为其充实一个测试“
theme-config.service.ts

@可注入({
providedIn:'根'
})
导出类ThemeConfigService{
建造师(
私有平台:平台,
专用路由器:路由器,
私人设置:设置服务
) {
//为简洁起见,删除了代码
}
}
下面是正在测试的服务“
settings.service.ts

@Injectable()
导出类设置服务{
构造函数(公共设置加载程序:设置加载程序,
公共navigationLoader:navigationLoader){}
公共设置():可观察{
返回此.settingsLoader.retrieveSettings();
}
公共导航():可观察{
返回此.navigationLoader.retrieveNavigation();
}
}
这是
设置加载程序
类,导航加载程序看起来完全一样。从设计角度来看,它们必须是独立的类:

导出抽象类设置加载程序{
抽象检索设置():可观察;
}
我的单元测试如下所示:

description('ThemeConfigService',()=>{
让服务:ThemeConfigService;
让路由器:路由器;
在每个之前(()=>{
TestBed.configureTestingModule({
进口:[
RouterTestingModule.withRoutes([])
],
供应商:[
平台,
设置服务,
设置加载程序,
导航加载器
]
});
路由器=试验台。注入(路由器);
service=TestBed.inject(ThemeConfigService);
});
它('应该创建'),异步(注入([平台、路由器、设置服务、设置加载程序、导航加载程序],
(平台:平台,路由器:路由器,设置:设置服务,设置加载程序:设置加载程序,导航加载程序:导航加载程序)=>{
expect(service.toBeTruthy();
})));
});
Karma返回的错误是:

TypeError: this.settingsLoader.retrieveSettings is not a function
which to me proves that it cannot resolve the abstract classes.
出于这个原因,我继续创作了这样的作品:

导出类设置MakeLoader扩展设置Loader{
retrieveSettings():可观察{
归还({});
}
}
并尝试使用这些更改
设置加载程序
导航加载程序
类的注入,然后Karma响应:

NullInjectorError: R3InjectorError(DynamicTestModule)[ThemeConfigService -> SettingsService -> SettingsLoader -> SettingsLoader]: 
  NullInjectorError: No provider for SettingsLoader!
对于
主题配置.service.spec.ts
文件,在每个
之前修改的

beforeach(()=>{
TestBed.configureTestingModule({
进口:[
路由模块,
RouterTestingModule.withRoutes([])
],
供应商:[
平台,
设置服务,
设置MakeLoader,
导航装载机
]
});
路由器=试验台。注入(路由器);
service=TestBed.inject(ThemeConfigService);
});
通常,我不会尝试测试我认为如此复杂的东西。也许我只是没有看到“解决方案”


任何帮助都将不胜感激,因为在这个应用程序的开发过程中,我将有一个类似的场景需要解决。

我选择了实例化路线,而不是依赖依赖依赖项注入。这可能不是一个可行的解决方案,并且仍然希望有人能以更好的方式回答最初的问题

更新的
主题配置.service.spe.ts
文件的
描述

description('ThemeConfigService',()=>{
让服务:ThemeConfigService;
let sLoader:设置sLoader;
让nLoader:NavigationLoader;
让服务:设置服务;
在每个之前(()=>{
TestBed.configureTestingModule({
进口:[
RouterTestingModule.withRoutes([])
],
供应商:[
经济服务,
设置服务,
设置加载程序,
导航加载器
]
});
let platform=TestBed.inject(平台);
let router=TestBed.inject(路由器);
sLoader=新设置MakeLoader();
nLoader=新导航fakeloader();
S服务=新设置服务(sLoader、nLoader);
服务=新ThemeSeconService(平台、路由器、sService);
});
它('应该创建',()=>{
expect(service.toBeTruthy();
});
});

我选择了实例化路线,而不是依赖依赖依赖项注入。这可能不是一个可行的解决方案,并且仍然希望有人能以更好的方式回答最初的问题

更新的
主题配置.service.spe.ts
文件的
描述

description('ThemeConfigService',()=>{
让服务:ThemeConfigService;
let sLoader:设置sLoader;
让nLoader:NavigationLoader;
让服务:设置服务;
在每个之前(()=>{
TestBed.configureTestingModule({
进口:[
RouterTestingModule.withRoutes([])
],
供应商:[
经济服务,
设置服务,
设置加载程序,
导航加载器
]
});
let platform=TestBed.inject(平台);
let router=TestBed.inject(路由器);
sLoader=新设置MakeLoader();
nLoader=新导航fakeloader();
S服务=新设置服务(sLoader、nLoader);
服务=新ThemeSeconService(平台、路由器、sService);
});
它('应该创建',()=>{
expect(service.toBeTruthy();
});
});

下面是一个很好的例子,说明了您在

您可以创建实现服务的公共API的任何类的实例,然后在配置测试模块时为该实例提供
useValue
beforeEach(() => {
  // stub UserService for test purposes
  userServiceStub = {
    isLoggedIn: true,
    user: { name: 'Test User' },
  };

  TestBed.configureTestingModule({
     declarations: [ WelcomeComponent ],
     providers: [ { provide: UserService, useValue: userServiceStub } ],
     // ^^^^^^ Note use of `useValue` ^^^^^^
  });

  fixture = TestBed.createComponent(WelcomeComponent);
  comp    = fixture.componentInstance;

  // UserService from the root injector
  userService = TestBed.inject(UserService);

  //  get the "welcome" element by CSS selector (e.g., by class name)
  el = fixture.nativeElement.querySelector('.welcome');
});