Угловое модульное тестирование - имитация асинхронных вызовов внедренных сервисов с помощью TestBed - PullRequest
0 голосов
/ 12 июня 2018

Мне нужно написать модульные тесты для следующих DataService,

@Injectable()
export class DataService {
   constructor(private config: ConfigService, private http: HttpClient) {

   }

   .....

   someMethod(){
        let apiUrl = this.config.get('api').url;   // LINE 1
   }
}

ConfigService вводится в DataService с функцией load, которая получает конфигурацию из файла json,Эта load функция будет вызываться при инициализации приложения.

export function configServiceFactory(config: ConfigService) {
    return () => config.load();
}

...

providers: [
        ConfigService,
        {
            provide: APP_INITIALIZER,
            useFactory: configServiceFactory,
            deps: [ConfigService],
            multi: true
        }
    ]

Вот часть файла data-service.spect.ts,

...

beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [
        HttpClientTestingModule
      ],
      providers: [DataService, ConfigService]
    });

    mock = TestBed.get(HttpTestingController);
    service = TestBed.get(DataService);
  });

....

, поэтому, когда я запускаю тест, в LINE 1 я получаю, что this.config.get('api') не определено.Я могу понять, что это потому, что ConfigService не загрузил данные из JSON.Итак, как я могу сделать так, чтобы внедренные сервисы также делали асинхронные вызовы во время модульных тестов?

1 Ответ

0 голосов
/ 12 июня 2018

При написании модульных тестов вы хотели бы смоделировать каждую вашу зависимость.Вы уже делаете это для HttpClient, импортируя HttpClientTestingModule, поэтому вам нужно сделать то же самое для ConfigService.

. Есть два способа сделать это.

1- Фальшивая служба (заглушка)

export class ConfigServiceStub {
    get(input: string) {
        // return static value instead of calling an API
    }
}

...

beforeEach(() => {
    TestBed.configureTestingModule({
        imports: [
            HttpClientTestingModule
        ],
        providers: [DataService, 
                   {provide: ConfigService, useClass: ConfigServiceStub}
        ]
    });

    mock = TestBed.get(HttpTestingController);
    service = TestBed.get(DataService);
});

Таким образом, ваш DataService не будет вызывать реальный ConfigService, а вместо этого 'вызовем get метод ConfigServiceStub.При использовании Stub s вам не нужно беспокоиться о других зависимостях ConfigService.Вы просто реализуете методы, которые хотите переопределить.

2-шпионы

Вы можете создать шпионов для метода, который вы не хотите вызывать.

it('run some test', inject([DataService], (service: DataService) => {
    spyOn(service.config, 'get').and.returnValue('someString');

    // run your tests here
});

Несмотря на то, что метод ConfigService.get не будет вызываться в приведенном выше примере, Angular по-прежнему необходимо создать экземпляр ConfigService, что может быть трудно сделать в некоторых примерах или может привести к созданиюслишком много других сервисов для простого теста.

Я бы выбрал вариант 1

Для получения дополнительной информации о шпионах, отметьте здесь

...