Chapter 13.3โ˜• 15 min read

Testing Services & HTTP

Services are simpler to test than components โ€” no template, no DOM. HTTP services need HttpClientTestingModule to mock requests. Pure logic services need only instantiation.

01Testing Basic Services

Testing simple services (no HTTP dependencies) is straightforward: instantiate and call methods.

// Pure logic service โ€” no dependencies
const service = new BiryaniService();
service.addBiryani({ name: "Test", price: 100 });
expect(service.getAll().length).toBe(1);

"Service test = pure function test โ€” input do, output check karo."

For services with Angular dependencies, use TestBed:

TestBed.configureTestingModule({
  providers: [BiryaniService]
});
const service = TestBed.inject(BiryaniService);

Service tests are much faster than component tests because there is no template compilation.

02Testing HTTP Services โ€” Setup

For services that make HTTP calls, use HttpClientTestingModule and HttpTestingController.

import { HttpClientTestingModule, HttpTestingController }
  from "@angular/common/http/testing";

let service: BiryaniService;
let httpMock: HttpTestingController;

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

"HttpClientTestingModule = fake server โ€” real request nahi jaata, mock response aata hai."

The HttpTestingController intercepts all HTTP requests and lets you assert on them.

03Testing GET Requests

Testing GET requests: Call the service method, expect the request, flush fake data.

it("should fetch biryanis", () => {
  const mockData = [{ id: 1, name: "Hyderabadi", price: 500 }];

  service.getBiryanis().subscribe(data => {
    expect(data.length).toBe(1);
    expect(data[0].name).toBe("Hyderabadi");
  });

  // Expect ONE request to /api/biryani
  const req = httpMock.expectOne("/api/biryani");
  expect(req.request.method).toBe("GET");

  // Flush fake response โ€” triggers subscribe callback
  req.flush(mockData);

  // Verify no unmatched requests remain
  httpMock.verify();
});

"Expect request, check method, flush fake response, verify."

04Testing POST/PUT/DELETE

Testing POST, PUT, DELETE โ€” same pattern as GET, just different methods.

it("should create a biryani (POST)", () => {
  const newBiryani = { name: "Hyderabadi", price: 500 };

  service.createBiryani(newBiryani).subscribe(data => {
    expect(data.id).toBe(1);
    expect(data.name).toBe("Hyderabadi");
  });

  const req = httpMock.expectOne("/api/biryani");
  expect(req.request.method).toBe("POST");
  expect(req.request.body).toEqual(newBiryani);  // Check body!

  req.flush({ id: 1, ...newBiryani });
  httpMock.verify();
});

it("should delete a biryani (DELETE)", () => {
  service.deleteBiryani(1).subscribe(() => {
    expect(true).toBeTrue();  // Just check it completes
  });

  const req = httpMock.expectOne("/api/biryani/1");
  expect(req.request.method).toBe("DELETE");
  req.flush(null);  // DELETE often returns 204 with no body
  httpMock.verify();
});

"Same pattern: call service, expect request, check body/method, flush response."

ALWAYS call httpMock.verify() to catch unexpected requests.

05Testing HTTP Errors

Testing error handling: Simulate server errors with req.flush() with an error.

it("should handle 404 error", () => {
  service.getBiryanis().subscribe({
    next: () => fail("Should have failed!"),
    error: (error) => {
      expect(error.status).toBe(404);
      expect(error.statusText).toBe("Not Found");
    }
  });

  const req = httpMock.expectOne("/api/biryani");
  req.flush("Not found", {
    status: 404,
    statusText: "Not Found"
  });
  httpMock.verify();
});

Network error simulation:

it("should handle network error", () => {
  service.getBiryanis().subscribe({
    error: (error) => {
      expect(error.status).toBe(0);  // Network error = status 0
    }
  });

  const req = httpMock.expectOne("/api/biryani");
  req.error(new ProgressEvent("error"));  // Simulate network failure
  httpMock.verify();
});

Always test BOTH success and error paths for every HTTP method.

Key Takeaways

  • Pure logic services: instantiate directly, no TestBed needed
  • HTTP services: use HttpClientTestingModule + HttpTestingController
  • expectOne() catches the request, flush() sends fake response
  • Always call httpMock.verify() at the end of each test
  • Test both success and error paths using flush() with error config
Course Search
Search across all chapters & stages
๐Ÿ“–

Search the course

Type any topic โ€” branching, stash, rebase, hooks โ€” and jump straight to that chapter.

merge branchesgit stashundo commitrebase