Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing Http Service making multiple calls and returning observable without mapping the responses

I have a data service which fetches the data from server and makes multiple requests which then return an array of observables. I want to test the data.

What i tried doing is in the mockrespone I sent array which contains two observables i dont know if thats the right way to test data.

But tests are failing especially the last three tests in the async test block

Important: I want to test that, when setting charId to falsy and comicsId to falsy, calling tthe method, subscribing to the observable it returns, after you've mocked http, you get back an array containing the two expected responses. Same with the 4 expected response if charId is truthy. Same for the 6 expected responses when comicsId is truthy

// the service which fetches the data

getChar(): Observable<any> {

    const Observables = [];
    Observables.push(this.http.get('https://gateway.marvel.com:443/v1/public/characters?apikey'));
    Observables.push(this.http.get('https://gateway.marvel.com:443/v1/public/comics?apikey'));

    if (this.charId) {
      Observables.push(this.http.get(`${this.urlChar}${this.charId}${this.apiKey}`));
      Observables.push(this.http.get(`${this.urlChar}${this.charId}/comics${this.apiKey}`));
    }
    if (this.comicsId) {
      Observables.push(this.http.get(`${this.urlCom}${this.comicsId}${this.apiKey}`));
      Observables.push(this.http.get(`${this.urlCom}${this.comicsId}/creators${this.apiKey}`));
    }
    console.log([Observable, Observable]);
    return Observable.forkJoin(Observables);
  }
}

// my test

import { async, ComponentFixture, TestBed, getTestBed, inject } from '@angular/core/testing';
import { MockBackend, MockConnection } from '@angular/http/testing';
import { DataService } from './data.service';
import {
  BaseRequestOptions, Http, XHRBackend, HttpModule,
  Response, ResponseOptions, RequestMethod
} from '@angular/http';
import { Observable } from 'rxjs/Observable';

describe('DataService', () => {
  let mockBackend: MockBackend;

   beforeEach(async(() => {
    TestBed.configureTestingModule({
      providers: [
        DataService,
        MockBackend,
        BaseRequestOptions,
        {
          provide: Http,
          deps: [MockBackend, BaseRequestOptions],
          useFactory:
          (backend: XHRBackend, defaultOptions: BaseRequestOptions) => {
            return new Http(backend, defaultOptions);
          }
        }
      ],
      imports: [
        HttpModule
      ]
    });
    mockBackend = getTestBed().get(MockBackend);
  }));


  it('should get ObservableArr', (done) => {
    let dataService: DataService;

    getTestBed().compileComponents().then(() => {
      mockBackend.connections.subscribe(
        (connection: MockConnection) => {
          connection.mockRespond(new Response(
            new ResponseOptions({
              body: [Observable, Observable]
            }
            )));
        });

      dataService = getTestBed().get(DataService);
      expect(DataService).toBeDefined();

      dataService.getChar().subscribe((obsArr: Observable<any>[]) => {
        expect(obsArr.length).toBeDefined();
        expect(obsArr.length).toEqual(2);
        expect(obsArr.length).not.toBe(1);
        done();
      });
    });
  });


  it('should check the service',
    inject([DataService], (service: DataService) => {
      expect(service).toBeTruthy();
    }));

  it('should get ObservableArray async',
    async(inject([DataService], (dataService: DataService) => {
      mockBackend.connections.subscribe(
        (connection: MockConnection) => {
          connection.mockRespond(new Response(
            new ResponseOptions({
              body: [Observable, Observable]
            }
            )));
        });
      dataService.getChar().subscribe(
        (response) => {
          expect(response.length).toBe(2);
          expect(response[0]).toBe(Observable); <<<<<<<<<<<<<< Fails
          expect(response[1]).toBe(Observable); <<<<<<<<<<<<<< Fails
          expect(response).toEqual([Observable, Observable]); <<<<<< Fails
        });
    })));
});
like image 951
SONGSTER Avatar asked Nov 01 '17 08:11

SONGSTER


People also ask

What is HttpClientTestingModule?

Using the HttpClientTestingModule and HttpTestingController provided by Angular makes mocking out results and testing http requests simple by providing many useful methods for checking http requests and providing mock responses for each request.


1 Answers

First of all, as @Aviad P. pointed, forkJoin method doesn't returns an Observable array of observables... it returns an array of the result of every observable in the forkJoin, and the result of that observables are not Observables instances.

Also, you are not mocking the getChart() method, with the mock backend you are mocking every http call, but not the method getChar() itself. The array must be length === 2 because not this.chartId and this.comicsId are present...

So I would say that the returned structure is something like that, so response[0] is an array:

response = [[Observable, Observable], [Observable, Observable]]

Said that, this expect will never be true, because no one array would be equal to a new array created:

expect(response).toEqual([Observable, Observable])

Modifying all that should resolve your problems. Also, In case your Observables returned and Observable instance, your code: ' body: [Observable, Observable] ' is not returning Observables instances, it is returning the Observable definition function, this would be a not correct mock, although the test would pass.

This would be a test example for ones is failing:

const mockResponse = {isMockResponse: true};

it('should get ObservableArray async',
async(inject([DataService], (dataService: DataService) => {
  mockBackend.connections.subscribe(
    (connection: MockConnection) => {
      connection.mockRespond(new Response(
        new ResponseOptions({
          body: {...mockResponse}
        }
        )));
    });
  dataService.getChar().subscribe(
    (response) => {
      expect(response.length).toBe(2);
      expect(response[0].isMockResponse).toBe(true); <<< Is this expect really necessary?
      expect(response[1].isMockResponse).toBe(true); <<< Is this expect really necessary?
    });
})));

Said that, The only expect that test your use case is this ones:

expect(response.length).toBe(2);

The other ones are unnecessary... so you are not testing the data you are mocking, you want to test the number of calls that has been performed due to the value of the variables this.chartId and this.comicsIs.

Hope this helps.

like image 176
Llorenç Pujol Ferriol Avatar answered Sep 17 '22 20:09

Llorenç Pujol Ferriol