Как обеспечить InjectionToken, у которого есть своя «фабрика»? - PullRequest
1 голос
/ 11 ноября 2019

Рассмотрим следующее InjectionToken для типа Foo:

export const FOO = new InjectionToken<Foo>(
  'foo token',
  { factory: () => new Foo() });

Теперь предположим, что я достаточно сумасшедший, чтобы стремиться к 100% тестированию покрытия. Для этого мне пришлось бы провести модульное тестирование этой маленькой factory функции.

Я думал создать инжектор, у которого в моем тесте будет только один поставщик:

const inj = Injector.create({
  providers: [{ provide: FOO }] // compiler error here
});

const foo = inj.get(FOO);

expect(foo).toBeTruthy();

К сожалению, этозавершается с ошибкой компилятора, поскольку { provide: FOO } не является допустимым поставщиком без свойства useValue, useFactory или useExisting. Но почему я вынужден определять один из них, когда токен впрыска поставляется с собственной фабрикой?

Конечно, я пробовал все варианты:

  • useValue: FOO компилируется и запускается,но, кажется, не выполняет фабричный метод
  • useFactory: () => FOO, deps: [] также компилируется и запускается, но, похоже, не выполняет фабричный метод, либо
  • useExisting: FOO компилируется, но завершается неудачно сциклическая ошибка зависимости во время выполнения

Достаточно забавно, похожий сценарий представлен в документации для InjectionToken, но он не показывает регистрацию, которую я ищу:

const MY_SERVICE_TOKEN = new InjectionToken<MyService>('Manually constructed MyService', {
  providedIn: 'root',
  factory: () => new MyService(inject(MyDep)),
});

// How is `MY_SERVICE_TOKEN` token provided?

const instance = injector.get(MY_SERVICE_TOKEN);

Я создал пример для StackBlitz , чтобы вы могли попробовать себя.

1 Ответ

1 голос
/ 11 ноября 2019

Когда вы указываете функцию factory для InjectionToken, токен автоматически предоставляется в корне. Поэтому вам не нужно предоставлять его на тестовом стенде.

Чтобы использовать эту функцию в тесте, вам нужно использовать TestBed вместо просто Injector.create.

import { TestBed } from '@angular/core/testing';

describe('Foo', () => {
  beforeEach(() => TestBed.configureTestingModule({}));

  it('should be created', () => {
    const service: Foo = TestBed.get(FOO);
    expect(service).toBeTruthy();
  });
});

Документы скажем

При создании InjectionToken вы можете при желании указать фабричную функцию, которая возвращает (возможно, путем создания) значение по умолчанию параметризованного типа T. Это устанавливает InjectionToken, используя эту фабрику в качестве провайдера, как если бы она была явно определена в корневом инжекторе приложения. Если фабричной функции, которая принимает нулевые аргументы, нужно ввести зависимости, это можно сделать с помощью функции inject. Ниже приведен пример.

...