如何在角度/茉莉花测试中模拟喷油器实例?



我需要测试我的服务,该服务使用Injector注入服务而不是constructor()

我使用这种方式的主要原因是大量的服务扩展了我的共同SimpleDataService。这里有CompanyServiceProductServiceTagService等,大家扩展了简单数据服务。所以我不想定义超过必要的参数来super()调用。

app.module.ts

import { Injector, NgModule } from '@angular/core';
export let InjectorInstance: Injector;
@NgModule({
// ...
})
export class AppModule {
constructor(private injector: Injector) {
InjectorInstance = this.injector;
}
}

simple-data.service.ts

import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { InjectorInstance } from 'src/app/app.module';
import { PaginateInterface } from 'src/app/models/paginate/paginate.interface';
import { environment } from 'src/environments/environment';
export class SimpleDataService<T> {
public url = environment.apiUrl;
private http: HttpClient;
public options: any;
public type: new () => T;
constructor(
private model: T,
) {
this.http = InjectorInstance.get<HttpClient>(HttpClient);
}
getAll(): Observable<PaginateInterface> {
return this.http.get(this.url + this.model.api_endpoint, this.options)
.pipe(map((result: any) => result));
}
}

simple-data.service.spec.ts

import { HttpClient } from '@angular/common/http';
import { TestBed } from '@angular/core/testing';
import { BrowserDynamicTestingModule,
platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
import { Tag } from 'src/app/models/tag/tag.model';
import { SimpleDataService } from './simple-data.service';
describe('SimpleDataService', () => {
TestBed.initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
const model = new Tag();
const simpleDataService = new SimpleDataService(model);
});

现在我收到TypeError: Object prototype may only be an Object or null: undefined错误消息。这是因为这一行:

this.http = InjectorInstance.get<HttpClient>(HttpClient);

InjectorInstance是这里的undefined

如何避免这种方式将Injector实例模拟到我的InjectorInstance属性中?

constructor(
private model: T,
private injectorInstance: Injector,
) { }

部分问题是您正在使用export let来声明InjectorInstance。这种类型的声明使得从任何其他文件(如:测试文件(修改字段是非法的。更改它的一种方法是使InjectorInstance成为AppModule类的静态字段,如下所示:

export class AppModule {
static InjectorInstance: Injector;
constructor(private injector: Injector) {
AppModule.InjectorInstace = injector;
}
}

然后,您可以使用该字段中的TestBed,因为Injector的接口实际上非常简单,仅包含get方法。如:

beforeEach(async(() => {
TestBed.configureTestingModule({(...)});
}));
beforeEach(() => {
AppModule.InjectorInstance = TestBed;
});

在当前的实现中,您还应该能够简单地执行以下操作:

new AppModule(TestBed)

我认为这一行的描述性较差,但它使您的InjectorInstance在生产代码中更安全。

请记住,所有这些都会使您的测试相互影响,因为一旦您更改该字段,它就会从其他所有测试的角度进行更改,即使在其他文件中也是如此。

将依赖关系注入模式交换为服务定位器模式是一个好主意是一个完全不同的讨论。

最新更新