Typescript — тестирование Angular, как обрабатывать http-запрос с параметрами, которые находятся внутри ngOnInit?

У меня есть модальный компонент, который получает входные данные извне и при открытии отправляет запрос на сервер для получения данных. После получения данных они присваиваются общедоступной переменной и используются для отображения данных. Как написать для него тест? Нужно ли издеваться над HttpClient? Или мне нужно предоставить все элементы @Input, а затем выполнить запрос как обычно? Но в этом случае мне нужно иметь реальные данные для внутреннего интерфейса, чтобы найти их в базе данных.

Я пробовал гуглить эту конкретную проблему, но ничего не нашел. Я нашел, как имитировать запросы, но не когда они находятся внутри ngOnInit(). Ниже я добавлю весь необходимый код.

составная часть:

enum Nav {
  General = 'General',
  SSL = 'SSL',
  Routes = 'Routes',
  Statistics = 'Statistics'
};

@Component({
  selector: 'app-mod-route-properties',
  templateUrl: './mod-route-properties.component.html',
  styleUrls: ['./mod-route-properties.component.scss']
})
export class ModRoutePropertiesComponent implements OnInit {

  @Input()
  title: string;

  @Input()
  resourceAddress: ResourceAddress;

  @Input()
  wgsKey: string;

  public emsRouteInfoData: EmsRouteInfoData;

  public sideMenuItems = Object.values(Nav);
  public active: string;
  Nav = Nav;

  constructor(
    private modRoutePropertiesService: ModRoutePropertiesService
  ) {
  }

  ngOnInit() {
    this.active = Nav.General;
    this.modRoutePropertiesService.getRouteProperties(this.resourceAddress, this.wgsKey).subscribe((res: EmsRouteInfoData) => {
      this.emsRouteInfoData = res;
    }, err => {
      console.log(err);
    });
  }
}

оказание услуг:

@Injectable()
export class ModRoutePropertiesService {

    constructor(
        private urlService: UrlService,
        private serverSettingsService: ServerSettingsService,
        private http: HttpClient
    ) { }

    public getRouteProperties(resourceAddress: ResourceAddress, wgsKey: string) {
        let token = this.urlService.getTokenByKey(wgsKey);
        let url = this.serverSettingsService.getRequestUrl('/route/properties');

        let headers = { 'x-access-token': token };
        let params = {
            manager: resourceAddress.manager,
            node: resourceAddress.node,
            qmgr: resourceAddress.qmgr,
            route: resourceAddress.objectName
        };
        const rq = { headers: new HttpHeaders(headers), params: params };

        return this.http.get<EmsRouteInfoData>(url, rq);
    }
}

сам тест:

describe('ModRoutePropertiesComponent', () => {
    let component: ModRoutePropertiesComponent;
    let fixture: ComponentFixture<ModRoutePropertiesComponent>;
    let httpMock: HttpTestingController;

    beforeEach(async(() => {
        TestBed.configureTestingModule({
            imports: [
                FormsModule,
                HttpClientTestingModule,
                NgbModule.forRoot(),
                RouterModule
            ],
            declarations: [
                AppComponent,
                ModRoutePropertiesComponent,
                ModalTitleComponent,
                ModRoutePropertiesGeneralComponent,
                ModRoutePropertiesSslComponent,
                ModRoutePropertiesRoutesComponent,
                ModRoutePropertiesStatisticsComponent,
                ModRoutePropertiesRouteSelectorComponent
            ],
            providers: [
                ModRoutePropertiesService,
                UrlService,
                TabsService,
                {
                    provide: Router,
                    useClass: class { navigate = jasmine.createSpy('tab'); }
                },
                NgbActiveModal,
                ServerSettingsService,
                ModErrorsDisplayService,
                ModalWindowService,
                LoadingIndicatorService
            ]
        })
            .compileComponents();
    }));

    beforeEach(() => {
        fixture = TestBed.createComponent(ModRoutePropertiesComponent);
        component = fixture.componentInstance;
        httpMock = TestBed.get(HttpTestingController);
        fixture.detectChanges();
    });

    it('should create', () => {
        expect(component).toBeTruthy();
    });

    it(`should init 'active'`, () => {
        expect(component.active).toBeDefined();
        expect(component.active).toEqual(component.Nav.General);
    });


    it(`should have initialized 'emsRouteInfoData'`, async(() => {
        expect(component.emsRouteInfoData).toBeDefined();
    }));
});

person Eivyses    schedule 01.02.2019    source источник
comment
Я, вероятно, притворюсь, что не знаю, что modRoutePropertiesService делает внутри. Поэтому я бы проверил, что правильные параметры передаются в modRoutePropertiesService.getRouteProperties, что будет издеваться. А затем проверьте, что компонент присваивает результат самому себе.   -  person Frank Modica    schedule 01.02.2019
comment
Как точно смоделировать запрос на обслуживание? Я не могу получить доступ к служебной переменной из-за того, что она является частной в компоненте. Я установил все переменные и могу получить их после ngOnInit, но теперь я хочу проверить, был ли запрос успешным и вернул ли данные, но последний тест не прошел. Или сервисные тесты каким-то образом свяжутся с этими и вернут результаты этих тестов?   -  person Eivyses    schedule 01.02.2019
comment
Похоже, TabsService издевается над useClass. Можете ли вы сделать то же самое? Макет будет иметь метод, который возвращает наблюдаемое с некоторыми тестовыми данными.   -  person Frank Modica    schedule 01.02.2019
comment
Похоже, мне также нужно создать ‹i›MockService‹/i› для моего ‹i›Service‹/i› и передать его в ‹i›useClass‹/i›. Я попробую это и обновлю тикет о том, как это происходит.   -  person Eivyses    schedule 01.02.2019


Ответы (1)


Я нашел решение. Итак, чтобы протестировать вызов запроса, который находится внутри метода ngOnInit, вам нужно следить за этой конкретной функцией запроса до вызова ngOnInit. Вместе с spyOn(service, 'function').and.returnValue(Observable.of(object)) он имитирует вызов запроса и возвращает указанные вами данные.
Для этого я удалил fixture.detectChanges() из beforeEach() тестовой заглушки. detechChanges() запускает цикл обнаружения изменений для компонента. После этого мой beforeEach() выглядит так:

beforeEach(() => {
        fixture = TestBed.createComponent(ModRoutePropertiesComponent);
        component = fixture.componentInstance;

        resourceAddress = new ResourceAddress();
        resourceAddress.node = 'Node';
        resourceAddress.manager = 'MANAGER';
        resourceAddress.qmgr = 'T1';
        resourceAddress.objectName = 'TestRoute';

        // setting inputs
        component.resourceAddress = resourceAddress;
        component.title = title;
        component.wgsKey = wgsKey;
    });

И после этого я переместил detectChanges() в конкретный тестовый пример, после того как смоделировал вызов нужной функции getRouteProperties.

it(`should have initialized 'emsRouteInfoData'`, async(() => {
        // needs 'Observable.of()' to simulate real Observable and subscription to it
        spyOn(service, 'getRouteProperties').and.returnValue(Observable.of(dummyRoute));
        // start ngOnInit
        fixture.detectChanges();
        expect(service.getRouteProperties).toHaveBeenCalled();
        expect(component.emsRouteInfoData).toBeDefined();
    }));
person Eivyses    schedule 04.02.2019