[Fixed] How to test API without mocks and spies?

Issue

There is the service that contains 2 methods:

export class CounterService {
  constructor(private http: HttpClient) {}

  getGirls(): Observable<any> {
    return this.http.get<any>('http://localhost:3000/girls');   // return some JSON
  }

  getObservableValue() {
    return of('observable value');
  }
}

I try to write unit-test:

describe('CounterService', () => {
  let service: CounterService;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [CounterService],
    });
    service = TestBed.inject(CounterService);
  });

  it(
    'test should wait for CounterService.getObservableValue',
    waitForAsync(() => {
      service
        .getObservableValue()
        .subscribe((value) => expect(value).toBe('observable value'));
    })
  );

  it(
    'test should wait for CounterService.getGirls',
    waitForAsync(() => {
      service
        .getGirls()
        .subscribe((value) => expect(value).toBeTruthy());
    })
  );
});

As a result test ‘test should wait for CounterService.getObservableValue‘ is successful, but test ‘test should wait for CounterService.getGirls‘ is not successful.

Jasmine displays the following message:

SPEC HAS NO EXPECTATIONS: test should wait for CounterService.getGirls

Please help me test getGirls() WITHOUT spy and any mocks. Is it possible at all?

Solution

You have to use the HttpTestingController to send requests.

describe('CounterService', () => {
  let service: CounterService;
  let httpTestingController: HttpTestingController;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [CounterService],
    });
    service = TestBed.inject(CounterService);
    httpTestingController = TestBed.inject(HttpTestingController);
  });

  afterEach(() => {
    // ensure no outstanding API calls
    httpTestingController.verify();
  });

  it(
    'test should wait for CounterService.getObservableValue',
    waitForAsync(() => {
      service
        .getObservableValue()
        .subscribe((value) => expect(value).toBe('observable value'));
    })
  );

  it(
    'test should wait for CounterService.getGirls',
    waitForAsync(() => {
      service
        .getGirls()
        .subscribe((value) => expect(value).toBeTruthy());

      const req = httpTestingController.expectOne('http://localhost:3000/girls');
      expect(req.request.method).toBe('GET');
      
      // flush this response
      req.flush(['Alicia', 'Tina', 'Michelle']);
    })
  );
});

This is a good blog post for you to help with Http testing.

Leave a Reply

(*) Required, Your email will not be published