Automated Front-End Unit Testing in Angular Framework (Part 2)
- Posted by Yomna Anwar
- On May 9, 2021
In the previous article, we discussed the different types of front-end testing and we have seen the libraries that Angular projects come bundled with to ease writing tests. Now, let’s see an example of how to test our view, components and how we can mock our component dependencies.
Mocking in Angular
When writing unit tests, you want to isolate the component being tested. And since we do not care much about injected dependencies and how do they behave. One concept that we must be familiar with when we write unit tests is mocking. So, what is mocking? It is the process of substituting any injected dependency in the component you want to test with fake or a mock to simulate this dependency behaviour. Remember, the key point in unit testing is to get the component you want to test in the right state also any dependency must behave in a certain way for you to be able to complete your unit test and therefore we must use MOCK. In the above example, we have used one of the Angular strategies for mocking and it is called spying. There are three ways to do mocking in Angular. Let us discuss them.
Mocking with fake classes
Mocking with a fake is a stub implementation, replacing the real implementation with a simplified fake one, as we know it as a dummy implementation. Let us refer to the previous article. If we want to mock the authentication service using a fake class, then we would create a class like this.
class AuthenticationServiceMock { canAccessUsers() { return true; } }
Now you can simply create an instance of that class and use it in the beforeEach
by assigning the newly created instance to the injected dependency inside your component.
component = fixture.componentInstance; component.authenticationService = new AuthenticationServiceMock();
When should you use a fake class? When the dependency you would like to mock is relatively simple.
Mocking by extending fakes and overriding methods
Like the previous method. You are going to create a new fake but this time the newly created class must extend from the original class you want to mock.
class AuthenticationService extends AuthenticationService { canAccessUsers() { return true; } }
Now you can simply create an instance of that class and use it in the beforeEach
by assigning the newly created instance to the injected dependency inside your component.
component = fixture.componentInstance; component.authenticationService = new AuthenticationServiceMock();
When should you use a fake class extension? When the dependency you want to mock is relatively complex and you only want to mock a couple of functions, not the whole class.
Mocking using a spy
Mocking with spy is the method used in the original example. A spy is basically listening to the calls made to a certain function, then intercepts these and changes the response based on the code you have written.
it('should have label and input field', () => { const compiled = debugElement.nativeElement; expect(compiled.querySelector('#requestEndDate').textContent).toContain('start date'); expect(compiled.querySelector('#contractEndDateInput')).toBeTruthy(); });
When should you use spying? When it is necessary for your test to assert that a function has been called. Or you want to write a relatively simple code.
Example tests
Testing Angular view part
it('should have label and input field', () => { const compiled = debugElement.nativeElement; expect(compiled.querySelector('#requestEndDate').textContent).toContain('start date') expect(compiled.querySelector('#contractEndDateInput')).toBeTruthy(); });
In this example, I am testing that a specific label and a field is rendered in the HTML.
Testing angular controller part
In the below example, I am testing that a specific function in my controller is called and that all the variables are assigned values correctly.
it('should display search results correctly', () => { component.updateListRequest(null, null, 1); expect(requestsApiServiceSpy.requestSearch).toHaveBeenCalled(); expect(component.filteredCases.length).toEqual(1); expect(component.cases.length).toEqual(1); expect(component.totalCases).toEqual(1); expect(component.dataFetched).toEqual(true); });
Running your tests
With the help of angular CLI, running angular tests is a matter of writing a single command to the terminal.
ng test