I've a injectable service (EntityApi) which extends a class (BaseApi). In my spec I like to mock the BaseApi with BaseApiStub. But it vain. Always calling the EntityApi.
// 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();
});
});
Expected Behavior is, while compile component in spec. It should call the BaseApiStub, instead it is calling BaseApi. I've seen a solution as below. But no luck.
export class BaseApiStub extends BaseApi { }
Test Code: stackblitz Check the console. I expect the You are on track!! log but received as Should not be here...
Not able to progress further. Can someone correct my mistake please.
What you are trying to do does not work. Dependency injection and class inheritance are not directly related. This means you cannot switch out the base class of your service like this.
As I see it you have two ways on how to do this.
Option 1:
Instead of mocking your BaseApi and providing the mock in your test you need to mock your EntityApi and provide this mock in your test.
Option 2:
Instead of letting your EntityApi extend from BaseApi, you could keep BaseApi a simple service and provide it as a dependency.
Instead of
class EntityApi extends BaseApi {
constructor(private injector: Injector) {
you do
class EntityApi {
constructor(private api: BaseApi) {
If you setup your EntityApi like this, it does not extend from BaseApi, but rather has it as a dependency. Then you can create a mock of the BaseApi and provide it like you did in your test.
Edit
Regarding your comment:
Since I should be using methods from BaseApi I cannot go without extends.
This is not true. Let's say the BaseApi has a method foo() that you want to use. When you extend your baseclass, the usage might look like this:
class EntityApi extends BaseApi {
constructor(private injector: Injector) {}
exampleMethod() {
this.foo();
}
}
If you just have the dependency you can still call the method like this:
class EntityApi {
constructor(private api: BaseApi) {}
exampleMethod() {
this.api.foo();
}
}
You don't need to extend from BaseApi in order to call methods on it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With