简体   繁体   中英

Angular mock multiple HTTP calls

I have one service which is returning the forkjoin of multiple http calls. I wanted to test this scenario.

    class CommentService{
     addComments(){

let ob1 = Observable.of({});
    let ob2 = Observable.of({});
if(any condition)
        ob1 = {this.http.post('/url/1')};
if(any condition)
            ob2 = {this.http.post('/url/2'};
        return Observable.forkJoin(ob1,ob2)
           }
     }

Above is my service class. How can i mock the http calls.

describe("CommentService", () => {
  let httpClient: HttpClient;
  let httpTestingController: HttpTestingController;
  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientModule, HttpClientTestingModule],
      providers: [CommentService]
    });

    httpClient = TestBed.get(HttpClient);
    httpTestingController = TestBed.get(HttpTestingController);
  });

  it('addComments() call with normal and gate', inject([CommentService], (service: CommentService) => {


    let cmts = service.addComments();

    const reqGateComment = httpTestingController.expectOne('/url/1');
    expect(reqGateComment.request.method).toEqual('POST');

    const reqFactComment = httpTestingController.expectOne('/url/2');
    expect(reqFactComment.request.method).toEqual('POST');

    reqGateComment.flush({});
    reqFactComment.flush({});


    httpTestingController.verify();

    cmts.subscribe(results=>{
       expect(results.length).toEqual(2);
    });

  }));


});

I am getting the below test fail. CommentService addFactsAndComments() call with normal and gate

Error: Expected one matching request for criteria "Match URL:

 '/url/1", found none.

I had a similar problem and I solved it using fakeAsync.

it('addComments() call with normal and gate', fakeAsync( inject([CommentService], (service: CommentService) => {

    service.addComments().subscribe(results=>{
        expect(results.length).toEqual(2);
     });

    const reqGateComment = httpTestingController.expectOne('/url/1');
    expect(reqGateComment.request.method).toEqual('POST');
    reqGateComment.flush({});

    tick(10000);

    const reqFactComment = httpTestingController.expectOne('/url/2');
    expect(reqFactComment.request.method).toEqual('POST');
    reqFactComment.flush({});


    httpTestingController.verify();

  })));

Thats because you are wrapping the observables created by the HttpClient in new ones by using the of method.

By doing

joined$ = forkJoin(obs$(post1$),obs$(post2$))

Note: $ stands for observable

You create a new observable that:

  • Subscribes to the outer obs$
  • Waits for them to complete,
  • Collects their last emited values (in this case post1$ and post2$)
  • Returns the collected values as an array in the order of the source streams

Because we only subscribed to the outer obs$ , your test is failing with

'/url/1", found none.

As we never subscribed to the inner post$, meaning that the requests werent sent.

Change your service method to:

addComments(){    
    const ob1 = this.http.post('/url/1');
    const ob2 = this.http.post('/url/2');

    return Observable.forkJoin(ob1,ob2);
 }

You need to call addComments and subscribe to the returned observable before you invoke expectOne . Only on subscription will the httpClient requests be triggered

That's the core issue here that's causing the test failure

You're right not to use fakeAsync btw as using HttpClientTestingModule is synchronous

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM