How mock object work in Angular jasmine unit test

15,643

Solution 1

The idea of mocking service is that you don't need to use the actual functionality (the real http call), but you do need the service methods to run your code without any exceptions.

For example: You have an component which in some point collect data from some API via Http. One of the unit test should test if you component make that call, but you are don't give a damn if there is a real call there. The point of your unit test is to test if the call has happened.

Edit: The same will happen if some of the inner logic make that call to collect a data to display something. You should mock the http call and return a data of your own. Your unit test shouldn't relly something from the outside. Imagine that your test will run on a enviroment without internet. The test should pass any time.

This scenario applies, no matter of the service you testing. The unit tests should have single responsability. They should not depend on anything different than their main purpose.

Solution 2

I have actually just ran into this issue in the past week so this is pretty fresh in my head. Jasmine confused me for a bit as well so I can share what I did to fix my issue.

To start, the Angular tutorials misleads new testers a little bit. It claims that we should use Jasmine, but then begins using TestBed and it is a little misleading. I ultimately went with TestBed and I can show you what I used.

So you have your describe:

descripe('randomService', () -> {

}

You need to initialize your `randomService':

descripe('randomService', () -> {
    let randomService: RandomService;         
}

using beforeEach(), you can re-init, assign values, etc. before each it statement within your describe.

descripe('randomService', () -> {
   let randomService: RandomService;         
   beforeEach(() => {
       imports: [
           HttpClientTestingModule
       ]
   });
}

So I am telling Angular to re-import the HttpClientTestingModule before each it block. My randomService requires HttpClient so I need to create a Jasmine Spy object, that returns what I tell it to instead of letting my randomService hit the actual backend and alter real data in my backend.

descripe('randomService', () -> {
   let randomService: RandomService;
   httpClientSpy;

   beforeEach(() => {
       imports: [
           HttpClientTestingModule
       ]
   });
   httpClientSpy = jasmine.CreateSpyObj('Http', ['get']);
   randomService = new RandomService(<any> httpclientSpy);       
}

So now whenever I do a 'get' method within my randomService, it will really be using the httpClientSpy, and it compiles because I told randomService that my argument was of type 'any' and to its' best knowledge, that is in fact a real HttpClient even when it is not. To use this properly, you must set up a fake return for your fake get:

descripe('randomService', () -> {
   let randomService: RandomService;
   httpClientSpy;
   mockResponse = { 1: ['first', 'second', 'third'] };
   beforeEach(() => {
       imports: [
           HttpClientTestingModule
       ]
   });
   httpClientSpy = jasmine.CreateSpyObj('Http', ['get']);
   randomService = new RandomService(<any> httpclientSpy);       
});

    it('should return first, second, third', () => {
        spyOn(httpClientSpy, 'get').and.returnValue(Observable.of(mockResponse));
        // randomService. <your get method here...>
        randomService.getValue().subscribe((response) =>
            expect(resposne[0].length).toEqual(3);
};
});

And that response should be the mockResponse that was created in our beforeEach() It does not have to be in the beforeEach(), but in this example I left it in there.

Share:
15,643
Always_a_learner
Author by

Always_a_learner

Have worked in below technologies: Backend: PHP (Laravel 5.1, zend framework 1.11, doctrine2), Node js(express framework), Python(Django). DB: MySQL, MS SQL, Mongodb Frontend: JQuery, Angularjs, Angular Currently working on: Frontend: Angular 2+, React JS

Updated on June 09, 2022

Comments

  • Always_a_learner
    Always_a_learner almost 2 years

    I am learning unit testing and Angular, so I am beginner in both. I have referred several tutorials and articles available on unit testing http in angular.

    I am not able to understand that what does httpMock does using HttpTestingController. We call function of actual service then why we call it mock? What is underlying process? Please refer some article to get better understanding.

    Thanks in advance.

    Edit: This is the issue where I stuck with httpMock.