How to Override Component Providers in Angular Unit Tests

Jared Youtsey
ngconf
2 min readMay 28, 2021

--

First, why do we need component-specific providers? Sometimes we need a 1:1 relationship between a component and a service. Services that are providedIn: "root" are application singletons (1:n). So, if we have two components we’ll have only one service instance. This doesn’t work in all scenarios. For example, if the service manages some private state, then two components using the same service can stomp on each other’s state value, or, if you’re doing reactive programming and creating a view model in a component that composes RxJS observables from a service that is specific to the component. In those cases, we need to provide the service in the component’s providers:

@Component({
...,
providers: [MyService]
})
export class MyComponent {}

The way we usually provide and mock services in our unit tests won’t work as expected in these cases. Let’s see that in action:

@Component({ 
providers: [ MyService ]
})
class MyComponent { }

TestBed.configureTestingModule({
declarations: [ MyComponent ]
providers: [ MyService ]
}).compileComponents();

let svc1 = TestBed.get(MyService);
let svc2 = fixture.debugElement.injector.get(MyService);

In the above case, svc1 is not the service being used by the component. It’s an application-wide singleton, but the component isn’t going to use it. svc2 is the service used by the component since we pulled that reference from the fixture’s injector. So, how do we mock that service?

We actually need to override the TestBed component:

const mockService = jasmine.createSpyObj('svc', ['method']);
TestBed.overrideComponent(
MyComponent,
{
set: {
providers: [{
provide: MyService,
useValue: mockService
}]
}
}
);
TestBed.configureTestingModule({
declarations: [ MyComponent ]
}).compileComponents();

We are using TestBed.overrideComponent to configure our component and pass in specific providers to the component. (FYI you can do a lot more with overrideComponent too.) Now, mockService is the instance that is provided toMyComponent. Easy!

Happy unit testing!

Now that you’ve read this article and learned a thing or two (or ten!), let’s kick things up another notch!
Take your skills to a whole new level by joining us in person for the world’s first MAJOR Angular conference in over 2 years! Not only will You be hearing from some of the industry’s foremost experts in Angular (including the Angular team themselves!), but you’ll also get access to:

  • Expert panels and Q&A sessions with the speakers
  • A friendly Hallway Track where you can network with 1,500 of your fellow Angular developers, sponsors, and speakers alike.
  • Hands-on workshops
  • Games, prizes, live entertainment, and be able to engage with them and a party you’ll never forget

We’ll see you there this August 29th-Sept 2nd, 2022. Online-only tickets are available as well.
https://2022.ng-conf.org/

--

--

Jared Youtsey
ngconf
Editor for

Passionate about JavaScript and Angular. Pure front-end development for the past eight years or so…