角度:如何在单元测试中模拟扩展类



>我有一个可注入的服务(EntityApi(,它扩展了一个类(BaseApi(。在我的规范中,我喜欢用BaseApiStub模拟BaseApi。但它是徒劳的。始终调用实体 Api。

// class
export class BaseApi { // want to mock BaseApi
constructor(injector: Injector) {
console.log("Should not be here...");
}
}
// service
@Injectable()
export class EntityApi extends BaseApi {
constructor(injector: Injector) {
super(injector, "entity");
}
}
// component
@Component({
selector: 'rt-entity-list',
templateUrl: './entity-list.component.html',
})
export class EntityListComponent {
api: any;
constructor(public entityApi: EntityApi) { 
this.api = entityApi;
}
}
// mock api
export class BaseApiStub { //mocked api
constructor() {
console.log("You are on track!!")
}
get() { }
}
// spec
describe('EntityListComponent', () => {
let component: EntityListComponent;
let fixture: ComponentFixture<EntityListComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [EntityListComponent],
providers: [ { provide: BaseApi, useClass: BaseApiStub }, // mocked class.
],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();

beforeEach(() => {
fixture = TestBed.createComponent(EntityListComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

预期行为是,同时在规范中编译组件。它应该调用 BaseApiStub,而不是调用 BaseApi。我已经看到了如下解决方案。但是没有运气。

export class BaseApiStub extends BaseApi { }

测试代码:堆栈闪电战 检查控制台。我希望你是 步入正轨!!日志,但收到不应该在这里...

无法进一步进步。有人可以纠正我的错误吗?

你尝试做的事情不起作用。依赖注入和类继承没有直接关系。这意味着您不能像这样切换服务的基类。

在我看来,你有两种方法可以做到这一点。

选项 1:

与其模拟您的 BaseAPI 并在测试中提供模拟,不如模拟您的 EntityApi 并在测试中提供此模拟。

选项 2:

与其让你的EntityApi从BaseApi扩展,你可以保持BaseApi一个简单的服务,并将其作为依赖项提供。

而不是

class EntityApi extends BaseApi {
constructor(private injector: Injector) {

是吗

class EntityApi {
constructor(private api: BaseApi) {

如果像这样设置 EntityApi,它不会从 BaseAPI 扩展,而是将其作为依赖项。然后,您可以创建 BaseAPI 的模拟并提供它,就像您在测试中所做的那样。

编辑

关于您的评论:

由于我应该使用 BaseApi 中的方法,因此我不能没有扩展。

这不是真的。假设 BaseApi 有一个你想要使用的方法 foo((。扩展基类时,用法可能如下所示:

class EntityApi extends BaseApi {
constructor(private injector: Injector) {}
exampleMethod() {
this.foo();
}
}

如果你只有依赖项,你仍然可以像这样调用该方法:

class EntityApi {
constructor(private api: BaseApi) {}
exampleMethod() {
this.api.foo();
}
}

您无需从 BaseAPI 扩展即可在其上调用方法。

如果您需要模拟父类的方法(例如指令(,您可以通过测试类的存根扩展来实现。

spyObject = {
methodToSpyOn(){}
};
@Directive({selector: '[myDirective]'})
class MyStubDirective extends MyDirective {
parentMethodToMock() {
return spyObject.methodToSpyOn();
}
}
spyOn(spyObject, 'methodToSpyOn').and.returnValue(true);

如果您的类在构造函数中具有父方法调用,则通常需要此方法

最新更新