45

Let's say I have a service that makes use of HttpClient,

@Injectable()
export class MyService {
  constructor(protected httpClient: HttpClient) { .. }
}

And then a component that makes use of this service.

@Component({
  selector: 'my-component'
})

export class SendSmsComponent {
  constructor(private MyService) { .. }
}

How to test this component while mocking the HttpClient and not the whole service?

TestBed.configureTestingModule({
  declarations: [MyComponent],
  providers: [
    { provide: MyService, useClass: MyService } // ?
  ]
}).compileComponents();

httpMock = TestBed.get(HttpTestingController); // ?
2
  • 6
    Considering that this is unit test, the proper way to do this is to mock the entire service. Commented Oct 25, 2017 at 11:03
  • and looking to this story in so helpful(walk before running) dev.to/zaklaughton/… Commented Oct 13, 2022 at 13:14

2 Answers 2

35

To mock HttpClient you can use HttpClientTestingModule with HttpTestingController

Sample code to accomplish the same

import { TestBed, ComponentFixture } from '@angular/core/testing';
import { Type } from '@angular/core';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { SendSmsComponent } from './send-sms/send-sms.component';
import { ApiService } from '@services/api.service';

describe('SendSmsComponent ', () => {
  let fixture: ComponentFixture<SendSmsComponent>;
  let app: SendSmsComponent;
  let httpMock: HttpTestingController;

  describe('SendSmsComponent ', () => {
    beforeEach(async () => {
      TestBed.configureTestingModule({
        imports: [
          HttpClientTestingModule,
        ],
        declarations: [
          SendSmsComponent,
        ],
        providers: [
          ApiService,
        ],
      });

      await TestBed.compileComponents();

      fixture = TestBed.createComponent(SendSmsComponent);
      app = fixture.componentInstance;
      httpMock = fixture.debugElement.injector.get<HttpTestingController>(HttpTestingController as Type<HttpTestingController>);

      fixture.detectChanges();
    });

    afterEach(() => {
      httpMock.verify();
    });

    it('test your http call', () => {
      const dummyUsers = [
        { name: 'John' },
      ];

      app.getUsers();
      const req = httpMock.expectOne(`${url}/users`);
      req.flush(dummyUsers);

      expect(req.request.method).toBe('GET');
      expect(app.users).toEqual(dummyUsers);
    });
  });
});
Sign up to request clarification or add additional context in comments.

1 Comment

Is all this code really necessary to mock HttpClient? Looks like a copy-past from your project code base. Where exactly does the magic happen? Some explanations would be useful.
21

This is the approach I follow while testing HttpClient

  1. Create mock HttpClient object

    const httpClientSpy = jasmine.createSpyObj('HttpClient', ['post', 'get']);
    
  2. Injecting mock object in providers

    providers: [{ provide: HttpClient, useValue: httpClientSpy }]
    
  3. Return dummy valued within beforeEach() or it()

    httpClientSpy.post.and.returnValue(of({ status: 200, data: {} }));
    httpClientSpy.get.and.returnValue(of({ status: 200, data: {} }));
    
  4. Example test case

    it('should return data for abc endpoint', () => {
      service.methodWithHttpRequest().subscribe(data => expect(data.status).toBe(200));
    });
    

1 Comment

and how to call httpClientSpy get method?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.