Angular testing how to prevent ngOnInit call to test a method directly
it(`should get the user List via refresh function`, fakeAsync(() => {
let ngOnInitFn = UserListComponent.prototype.ngOnInit;
UserListComponent.prototype.ngOnInit = () => {} // override ngOnInit
comp.onRefreshUserList();
tick();
fixture.detectChanges();
UserListComponent.prototype.ngOnInit = ngOnInitFn; // revert ngOnInit
expect(comp.userList.length).toBe(3, 'user list after function call');
}));
Plunker Example
Preventing lifecycle hook (ngOnInit
) from being called is a wrong direction. The problem has two possible causes. Either the test isn't isolated enough, or testing strategy is wrong.
Angular guide is quite specific and opinionated on test isolation:
However, it's often more productive to explore the inner logic of application classes with isolated unit tests that don't depend upon Angular. Such tests are often smaller and easier to read, write, and maintain.
So isolated tests just should instantiate a class and test its methods
userManagementService = new UserManagementServiceStub;
comp = new UserListComponent(userManagementService);
spyOn(comp, 'getUserList');
...
comp.ngOnInit();
expect(comp.getUserList).toHaveBeenCalled();
...
comp.onRefreshUserList();
expect(comp.getUserList).toHaveBeenCalled();
Isolated tests have a shortcoming - they don't test DI, while TestBed tests do. Depending on the point of view and testing strategy, isolated tests can be considered unit tests, and TestBed tests can be considered functional tests. And a good test suite can contain both.
In the code above should get the user List via refresh function
test is obviously a functional test, it treats component instance as a blackbox.
A couple of TestBed unit tests can be added to fill the gap, they probably will be solid enough to not bother with isolated tests (although the latter are surely more precise):
spyOn(comp, 'getUserList');
comp.onRefreshUserList();
expect(comp.getUserList).toHaveBeenCalledTimes(1);
...
spyOn(comp, 'getUserList');
spyOn(comp, 'ngOnInit').and.callThrough();
tick();
fixture.detectChanges();
expect(comp.ngOnInit).toHaveBeenCalled();
expect(comp.getUserList).toHaveBeenCalledTimes(1);