What's the difference between TestBed.get and new Service(...dependencies)
Asked Answered
B

3

17

The angular guide demonstrates two different ways of testing, one by calling new Service() and providing the dependencies to the constructor directly, and the second using dependency injection by calling TestBed.get(Service).

Both of these seem functionally identical to me, except when I call TestBed.get() consecutively it does not call the constructor after the first call.

The angular documentation also mentions that TestBed.get() is deprecated (even though the guide still references it!) and that I should use Type or InjectionToken instead, but I do not see how either of these classes could replace TestBed.get().

Brushoff answered 26/6, 2019 at 15:23 Comment(0)
S
24

Deprecated from v9.0.0 use TestBed.inject

get(token: any, notFoundValue?: any): any

See how can we inject now:

describe('MyAmountComponent', () => {
  let component: MyAmountComponent;
  let fixture: ComponentFixture<MyAmountComponent>;
  let productService: ProductService;
  let orderService: OrderService;
  beforeEach(() => {
    TestBed.configureTestingModule({
       .....
    })
    .compileComponents();
    productService = TestBed.inject(ProductService);
    orderService = TestBed.inject(OrderService);
  });

Just adding so might can help someone.

Sitarski answered 8/8, 2020 at 18:20 Comment(0)
S
9

When you call TestBed.configureTestingModule({ providers: [SomeService] });, this sets up an NgModule that can be used in subsequent tests. If you call TestBed.get(SomeService), this retrieves SomeService from the injector and instantiates it if needed. If it is instantiated, then the injector injects references to it's dependencies and returns a new instance of the service.

If SomeService has already been instantiated, as in your case, then the TestBed does not need to create it. This means that it won't call the constructor a subsequent time.

To answer your question about the difference, basically they are the same if you are mocking all of your dependencies and if you don't need to access the DOM. Instantiating classes without the TestBed is significantly faster because there isn't the overhead of loading the dependency injector for every test.

As for the TestBed.get() being deprecated, in Angular 8.0.0, only the specific overload that allows any type was deprecated (see https://github.com/angular/angular/blob/master/packages/core/testing/src/test_bed.ts#L67). Instead of get(token: any, notFoundValue?: any): any; the signature was changed to get<T>(token: Type<T> | InjectionToken<T>, notFoundValue?: T, flags?: InjectFlags): any; which means that you had to use a class reference or injection token. No strings or other things to reference something in the injector.

In Angular 9.0.0, the TestBed.get() method will be fully deprecated and you will need to use TestBed.inject instead. See https://github.com/angular/angular/blob/master/packages/core/testing/src/test_bed.ts#L65

Shaitan answered 10/10, 2019 at 21:8 Comment(0)
J
5

get is deprecated: from v9.0.0 use TestBed.inject (deprecation)

let valueServiceSpy: jasmine.SpyObj<ValueService>;

beforeEach(() => {
  const spy = jasmine.createSpyObj('ValueService', ['getValue']);

  TestBed.configureTestingModule({
    providers: [
      { provide: ValueService, useValue: spy }
    ]
  });
  // This is new way to inject Spied Service
  valueServiceSpy = TestBed.inject(ValueService) as jasmine.SpyObj<ValueService>; 
});

and then in tests

it('#getValue should return stubbed value from a spy', () => {
  valueServiceSpy.getValue.and.returnValue(yourValue);
  ...
});

Official Doc: https://v9.angular.io/guide/testing#angular-testbed

Janina answered 31/12, 2020 at 9:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.