What advantages does utilizing Jasmine Spy Object provide in Angular Unit Testing?

I have a question regarding unit testing in Angular using Jasmin/Karma.

Currently, I am working with three services: EmployeeService, SalaryService, and TaxationService.

The EmployeeService depends on the SalaryService, which is injected into its constructor.

Similarly, the SalaryService depends on the Taxation service, which is also injected into its constructor.

In my employee.component.spec.ts file, the following code snippet can be found:

let employeeService: EmployeeService;
let salaryServiceSpy: jasmine.SpyObj<SalaryService>;

TestBed.configureTestingModule({
 providers: [EmployeeService],
 declarations: [ EmployeeComponent ]
})
.compileComponents();
  employeeService = TestBed.inject(EmployeeService);
  salaryServiceSpy = TestBed.inject(SalaryService) as jasmine.SpyObj<SalaryService>;
}));

it('should return Name and Salary', () => {
  expect(employeeService.getEmployeeNameAndSalary(1)).toBe("John Smith receives: $12345 and tax value of 15%");
});

While the code seems to be functioning correctly, I'm puzzled about the necessity of using Jasmine Spy. The code runs fine even without implementing the spy service?

 salaryServiceSpy = TestBed.inject(SalaryService) as jasmine.SpyObj<SalaryService>;

I came across this example for reference: https://angular.io/guide/testing-services.

If we consider the example below, why do we need to create the ValueServiceSpy? Doesn't TestBed.inject already handle the injection of all dependencies and the 'dependencies of the other dependencies'?

https://i.sstatic.net/bGeWP.png

Answer №1

Allow me to elaborate, I faced similar queries myself a few years ago :

What is the significance of utilizing Jasmine Spy Object in Angular Unit Testing?

Response: The use of a spy grants you the ability to perform the following tasks in unit tests:

  1. You can verify whether a function has been invoked or not (by utilizing `expect(component.method).toHaveBeenCalled())

  2. You can also modify the actual implementation within service.ts and provide dummy data for different test scenarios.

You can refer to this article where Stubs were employed instead of what is typically recommended in the angular guide. Stubs were used because they can be reused in other other-component.spec.ts files that utilize the same service by injecting it through providers with useClass. Take your time to observe how .toHaveBeenCalled() was utilized [ to comprehend point 1 ] , as well as how .returnValue() was used to mimic the error behavior of a service.


Why create the ValueServiceSpy? Doesn't TestBed.inject already inject all dependencies along with their 'dependencies of the other dependencies'?

Response: Indeed, TestBed.inject does inject dependencies, but it injects the actual ValueService. In unit testing, the objective is to isolate the " service being tested " (in this case, the focus is on testing MasterService rather than ValueService) .

Thus, it is logical to mock the ValueService while conducting tests on the MasterService.


Does that clarify things for you?

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Uploading files with Angular 4 and Rails 5 using paperclip

I am currently engaged in a project that involves an Angular 4 frontend and a Rails 5 API backend. I'm facing an issue with uploading videos using paperclip, as they are not getting saved to the database for some unknown reason. Despite all the parame ...

I encountered a frustrating issue of receiving a 400 Bad Request error while attempting to install

I am currently in the process of installing Angular CLI using npm to incorporate Angular 4 into several projects. Unfortunately, I keep encountering a 400 Bad Request error. Has anyone else faced this issue before and found a solution? I have already searc ...

AngularJS: encountering an undetected object due to interdependencies between services and modules

I have a module called 'maps-services' with a service named 'MapService' defined as follows: angular.module('maps-services', []) .service('MapService', [$log, function($log) { this.initMap = function() { } ...

Combining array elements into functions with RxJS observables

I am facing a scenario where I have an array of values that need to be processed sequentially using observables in RxJS. Is there a more optimized way to achieve this instead of using nested subscriptions? let num = 0; let myObs = new Observable(obs ...

Unexpected behavior with Angular 10 behavior subject - encountering null value after invoking .next(value) function

Can anyone help me solve the mystery of why my user value turns null after I log in? This is the login page where an API is called and the result is obtained as shown below: https://i.stack.imgur.com/kDjSy.png Here is the authentication service implemen ...

Creating a Tailored Validation Function in Angular 6

Looking to develop a custom generic validator that accepts the regular expression pattern and the property name (from a formgroup) as parameters? Take a look at this code snippet: UserName: new FormControl('', [ Validators.require ...

Issue encountered in app.module.ts while attempting to incorporate AngularMultiSelectModule

Currently, I am utilizing angular version 6 and attempting to incorporate the angular2-multiselect-dropdown in my application. Upon launching the app and following the steps outlined in this guide: and also here: https://www.npmjs.com/package/angular2-mul ...

Expanding a TypeScript type by creating an alias for a property

I am working on defining a type that allows its properties to be "aliased" with another name. type TTitle: string; type Data<SomethingHere> = { id: string, title: TTitle, owner: TPerson, } type ExtendedData = Data<{cardTitle: "title&qu ...

What steps should I take to address the issue of sanitizing a potentially harmful URL value that contains a

I've encountered a URL sanitization error in Angular and despite researching various solutions, I have been unable to implement any of them successfully in my specific case. Hence, I am reaching out for assistance. Below is the function causing the i ...

Deleting elements from an array of objects in Angular Would you like help with

I have a JSON structure and I need to remove the entire StartGeotag object from the array. [{ CreatedDate: "2022-02-17T10:30:07.0442288Z" DeletedDate: null ProjectId: "05b76d03-8c4b-47f4-7c20-08d9e2990812" StartGeotag: { ...

Tips for integrating 2 way data binding into model-driven forms

When working with Angular 2, one approach to creating forms is the model-driven method. This means that controls may lose their two-way data binding, unlike in the template-driven approach with ngModel. What is the best way to combine two-way data binding ...

Creating a structured state declaration in NGXS for optimal organization

Currently, I'm delving into the world of NGXS alongside the Emitters plugin within Angular, and I find myself struggling to grasp how to organize my state files effectively. So far, I've managed to define a basic .state file in the following man ...

Pause and anticipate the occurrence of AdMob's complimentary video reward event within a defined function in Ionic/Typescript

In my ionic app, I have a function that determines if the user has watched a reward video to access another function: let canUseThisFunction = await this.someService.canUseFunction(); if(canUseThisFunction){ console.log("can use"); } else { cons ...

ngFor directive not iterating properly without any errors being displayed in the console

I reviewed numerous inquiries about issues with "ngFor not functioning properly". Here are the specifics. app.modules.ts import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; impo ...

Angular - Dividing Functionality into Multiple Modules

I am currently working with two separate modules that have completely different designs. To integrate these modules, I decided to create a new module called "accounts". However, when I include the line import { AppComponent as Account_AppComponent} from &a ...

Angular is able to select an element from a specified array

I'm currently struggling with using Angular to manipulate a TMDB API. I am having difficulty retrieving an item from an array. Can someone provide assistance? Here is the response that the array returns: { "id": 423108, "results ...

Calculate the total sum of an array in Angular based on a specific condition of another key

How do I calculate the sum of array elements where sel1, sel2, or sel3 is equal to 1 from the following Array? [ { "sel1": 0, "sel2": 1, "sel3": 0, "price": 10 }, { "sel1": 0, "sel2": 1, &qu ...

Issue with uncaught exceptions in promise rejection test

I am experiencing an issue with the following code: function foo(){ bar().catch(function(){ //do stuff } } function bar(){ return promiseReturner().then( function(result){ if(_.isEmpty(result)){ throw "Result is empty"; ...

The VSCode's intellisense for Angular Material fails to function effectively

In the midst of my project on Angular version 13, I have successfully installed Angular Material using the command below: ng add @angular/material The package has been properly included in the node_modules folder. However, when working with TypeScript ...

The status of the Office.js appointment remains updated even after the saveAsync callback is executed

Utilizing the Office JavaScript API for an Outlook add-in, I encountered a issue with some code designed to save an appointment and close its window. Despite saving the appointment through the API, I continue to receive a "Discard changes" confirmation dia ...