6 min to read
Jasmine
Today I bring you a little dose of #codeflix! These days I couldn’t find much inspiration (?) and now let’s say that…. neither
Well today’s post is dedicated to Jasmine. Unit testing is a topic that I don’t always like so I wanted to bring some concepts and exercises to make you want to raise that coverageeeee of your component or service!
Test configuration
Well, when we want to start building the test suit of an existing component, the first thing we do is to create the spec file, with exactly the same name of our component in question, example: home.component.ts —> home.component.spec.ts.
*Note: the subject of the name is merely for convention and organization.
In that file, we put the base of the test suit something like this:
describe('HomeComponent Test', () => {
let component: HomeComponent ;
let fixture: ComponentFixture<HomeComponent>;
beforeEach(() => TestBed.configureTestingModule({
declarations: [HomeComponent]; => TestBed.configureTestingModule({ declarations: [HomeComponent
imports: [],
providers: []
}));
beforeEach(() => {
fixture = TestBed.createComponent(HomeQuoteFormComponent);
component = fixture.componentInstance;
});
it('should be created', () => {
expect(component).toBeTruthy();
});
On this base structure we are going to work and we are going to try to verify that our component really is created. In order to make this base work, we have to configure a little bit the configureTestingModule, which works exactly the same as the dependency injection that we perform with the @NgModule of Angular.
In this case we are going to limit ourselves to import what is necessary for the component to be created, as well as in providers the services that it needs for its implementation and that we can find in the constructor of the existing component that we want to test. In declarations the idea is to leave only the component that we want to test, to favor the isolation and focus on testing only our component, without getting into sub components or parent components. In order to avoid that our test runner (Karma) requires us that we have own components parents or children that are related to our HomeComponent, there is a property that we can use called schemas:.
And we use it like this:
schemas: [CUSTOM_ELEMENTS_SCHEMA],
With that we tell it that our component will be related to others, but that we do not want to import all those dependencies because we are only going to test our component, performing unit testing and not functional testing or integration tests.
The most common thing also, is that in providers it asks for the RouterTestingModule, HttpClientTestingModule, they are not always necessary but if it asks for it when we execute ng test we will have to apply it.
There are different ways to mockear the services, which is perhaps the most interesting and challenging part when mockear the configuration of our component to be able to begin to test it.
Jasmine Spies
A spy basically serves us NOT to call the real method with its arguments, but it mocks the function that we ask for pretending that it was called, and it omits all the implementation that the function has even its return.
To work with spies, we only need first in provider to add the service(s) that the component needs in its constructor:
providers: [HomeService]
and then in the beforeEach we add it, we would be left with:
beforeEach(() => {
fixture = TestBed.createComponent(HomeQuoteFormComponent);
component = fixture.componentInstance;
homeService = TestBed.get(HomeService);
});
In our HomeService we will surely have our own methods and class variables of the service that we have created, but so that the home component is created, we only need to mockear, in first instance, the methods/properties that we are using in the cycle ngOnInit() of our component. With a Spy we would be left with:
getContentSpy = spyOn(homeService, 'getContent');
and ready, if we are making a this.homeService.getContent(); in our onInit, the previous spy will work by mocking that method so that the component can be created.
Test Doubles
Another way to mock or simulate how our services that are dependent on our component work, is to manage them as Stubs.
What does this mean? That we can have a class that simulates to be our service, it will have exactly the same methods (or at least only the necessary ones that our component uses) and class variables if necessary, with what we want it to return.
To apply this method we only have to create a file and export this class, for example home.service.stub.ts and that contains:
export class HomeServiceStub {
getContent(): void {
return 'holis';
}
}
We import this file in our spec and in providers, we are going to tell our configuration that instead of using the real service that has the provider of the component, to use ours that we just created, how do we tell it?
providers: [
{ provide: HomeService, useClass: HomeServiceStub },
]
and that’s it
Conclusion
In all the previous example we could see, how to create and generate a spec from scratch, for a given existing component, its base configuration that covers its initialization, and an example of dependency with a specific service, which makes a call to a getContent() method within the OnInit cycle.
We also saw in two different ways how we mocke the method of that service, so that our component can be initialized and created correctly.
What is the difference?
If we do it with the first option of the Spy, we will have possibilities to access the methods that Jasmine offers us to test, for example if we want to test if it was called, we will be able to do it simply like this:
expect(homeServiceSpy).toHaveBeenCalled();
and any other Jasmine method we want to use.
In the second way we can’t trace or use those methods, but we can use it to mock the whole service or part of it.
Neither option is the best or the most suitable, it simply depends on what we need to test and what our coverage covers, for some occasions we will want to test and track the calls so we will use spies, and at other times we will only need to mockear and focus our testing in other aspects.
In the next post I will detail different spies and other ways of stubbing, not to extend today’s reading :)