DEV Community

Cover image for Angular: Unit Test Mock Service
bob.ts
bob.ts

Posted on

7 1

Angular: Unit Test Mock Service

So, I needed to mock a service.

In particular, I wanted to mock the API Handler Service. This service is the abstraction layer I use to interact with the back-end. There's often a lot going on here.

When testing other code, I wanted to mock the calls and data responses to ensure stability.

Mocking Tools

While there are a lot of tools that can mock or replace an HTTP server, what I wanted to do was mock THIS service so that other code had consistent data coming back.

Starting Code

I started with something like this ...

// createSpyObj returns the attached OBJECT,
// if a function is attached, that is what is
// returned (not executed).
let MockApiHandlerService = jasmine.createSpyObj('ApiHandlerService', {
  ...
  getChartData: Promise.resolve(chartData),
  getEventDetail: Promise.resolve(eventDetail),
  getEventSummary: Promise.resolve(eventSummary),
  ...
});

export default MockApiHandlerService;
Enter fullscreen mode Exit fullscreen mode

Yes, there are a lot of other functions I am not covering. These show the basics. The chartData, eventDetail, and eventSummary are data points listed higher in the file that I could use as mock data.

This code worked great.

And YES, I left the comment in ... after creating functions to execute. I have this on any jasmine.createSpyObject in my code to remind me.

These values are what are returned ... regardless of what is passed to the function.

Tying this into Jasmine

First, the actual and mock service need imported ...

import { ApiHandlerService } from '@core/services/api-handler.service';
import MockApiHandlerService from '@shared/_spec-tools/mock-api-handler.service';
Enter fullscreen mode Exit fullscreen mode

Then, in the beforeEach, providers the services are used like this ...

beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [ ... ],
      declarations: [ ... ],
      providers: [
        { provide: ApiHandlerService, useValue: MockApiHandlerService }
      ]
    })
    .compileComponents();
  });
Enter fullscreen mode Exit fullscreen mode

Issues

Changing the Value

The first issue I has was that I wanted different data returned on one of the functions.

What I found was that I was changing the value returned for other tests doing something like this.

MockApiHandlerService.getUsers.and.returnValue(Promise.resolve(null));
Enter fullscreen mode Exit fullscreen mode

What I wound up having to do to correct this was to capture the "old" value and replace it after the test expects ...

const oldValue = MockApiHandlerService.getUsers;
MockApiHandlerService.getUsers.and.returnValue(Promise.resolve(null));

...
MockApiHandlerService.getUsers = oldValue;
Enter fullscreen mode Exit fullscreen mode

Resetting the Calls

Additionally, I ran into issues resetting calls and checking to see the number of times a service function was called in a test.

Initially, I was clearing them per test, but after the first time I implemented something like this ...

// createSpyObj returns the attached OBJECT,
// if a function is attached, that is what is
// returned (not executed).
let MockApiHandlerService = jasmine.createSpyObj('ApiHandlerService', {
  ...
  getChartData: Promise.resolve(chartData),
  getEventDetail: Promise.resolve(eventDetail),
  getEventSummary: Promise.resolve(eventSummary),
  ...
});

MockApiHandlerService._reset = () => {
  MockApiHandlerService.getChartData.calls.reset();
  MockApiHandlerService.getEventDetail.calls.reset();
  MockApiHandlerService.getEventSummary.calls.reset();
};

export default MockApiHandlerService;
Enter fullscreen mode Exit fullscreen mode

This pattern then allowed me to clear the calls before each test run ...

beforeEach(() => {
  MockApiHandlerService._reset();
});
Enter fullscreen mode Exit fullscreen mode

Summary

Throughout this process, I learned a lot of things about mocking a service. In particular, one that was used as frequently as this one throughout the application.

When testing other code, I wanted to mock the calls and data responses to ensure stability. With the mock service above, I was able to attain all the stated goals.

Image of AssemblyAI tool

Transforming Interviews into Publishable Stories with AssemblyAI

Insightview is a modern web application that streamlines the interview workflow for journalists. By leveraging AssemblyAI's LeMUR and Universal-2 technology, it transforms raw interview recordings into structured, actionable content, dramatically reducing the time from recording to publication.

Key Features:
🎥 Audio/video file upload with real-time preview
🗣️ Advanced transcription with speaker identification
⭐ Automatic highlight extraction of key moments
✍️ AI-powered article draft generation
📤 Export interview's subtitles in VTT format

Read full post

Top comments (1)

Collapse
 
codejs_in_e6d21569ba061b profile image
code-js in

"Please take a moment to read the post I have shared on the website listed below. I believe it contains valuable information that you will find useful."

Understanding Unit Testing in Angular: Mocked Service API Calls and Component Rendering

Heroku

Simplify your DevOps and maximize your time.

Since 2007, Heroku has been the go-to platform for developers as it monitors uptime, performance, and infrastructure concerns, allowing you to focus on writing code.

Learn More

👋 Kindness is contagious

Immerse yourself in a wealth of knowledge with this piece, supported by the inclusive DEV Community—every developer, no matter where they are in their journey, is invited to contribute to our collective wisdom.

A simple “thank you” goes a long way—express your gratitude below in the comments!

Gathering insights enriches our journey on DEV and fortifies our community ties. Did you find this article valuable? Taking a moment to thank the author can have a significant impact.

Okay