Why should we use Jasmine Spy Object in Angular Unit Testing?

Viewed 2068

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

I have 3 services as below: EmployeeService, SalaryService and TaxationService.

EmployeeService depends on SalaryService which is injected in it's constructor.

SalaryService depends on Taxation service which is again injected in it's constructor.

In my employee.component.spec.ts, I have the below code:

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%");
});

The code works fine, my question is why do we need to use Jasmine Spy - the code works fine without the spy service as well?

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

I have used the below as reference: https://angular.io/guide/testing-services.

If below example is more clear, what is the need to create the ValueServiceSpy? Does the TestBed.inject not already inject all dependencies and the 'dependencies of the other dependencies'?

enter image description here

1 Answers

Let me explain, I also had similar questions few years back :

Why should we use Jasmine Spy Object in Angular Unit Testing?

Answer: Because when you create spy , you get the power to do below tasks in unit tests:

  1. You can check whether the function has been called or not (by using `expect(component.method).toHaveBeenCalled())

  2. You can even override the actual implementation (written inside service.ts) and return some dummy data to create several scenarios for unit test cases.

You check this article where I used Stubs unlike what you can see in angular guide. I used Stubs because I can reuse it other other-component.spec.ts which uses the same service, by simply injecting in providers using useClass. Take your time and see how I used .toHaveBeenCalled() [ to understand my point 1 ] , and also how I used .returnValue() to recreate the error behavior of service.


What is the need to create the ValueServiceSpy? Does the TestBed.inject not already inject all dependencies and the 'dependencies of the other dependencies'?

Answer: Yes, TestBed.inject did inject the dependencies but it injects the actual ValueService. For unit testing you want to isolate the " service which you want to test " (in this case, you want to test MasterService and not ValueService) .

So, it makes sense to mock the ValueService while testing MasterService.


Does that make sense ?

Related