Как протестировать угловой сервис с призывом подписаться на него? - PullRequest
0 голосов
/ 21 октября 2019

У меня есть служба под названием page.service.ts. Я хочу проверить его loadPage(path: string) метод. Но я не могу выполнить блок subscribe из файла спецификации. Когда я запускаю тест, я вижу load Page called, напечатанный на консоли, но Subscribe is being executed никогда не печатается.

Пожалуйста, смотрите файл сервиса и спецификации ниже:

import { Injectable } from '@angular/core';
import { Page } from '../models/page.model';
import { environment } from '../../environments/environment';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject, Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class PageService {

  public currentPath: string;
  public page = new BehaviorSubject<Page>(null);

  constructor(private http: HttpClient) {}

  public loadPage(path: string) {
    this.currentPath = path;
    console.log('load Page called');
    const request_url = environment.apiBaseURL + 'api/structure/page/';
    console.log(request_url);
    const request = this.http.get(request_url,  {
      params: {
        path: this.currentPath + '/'
      }
    });

    request.subscribe(
      (results: any) => {
        console.log('Subscribe is being executed');
        const p = new Page().deserialize(results);
        p.path = path;

        this.page.next(p);
      }
    );
  }

  isActivePage(page: Page) {
    return this.currentPath === page.path;
  }
}

файл спецификации:

import { TestBed, fakeAsync, flush, tick } from '@angular/core/testing';

import { PageService } from './page.service';
import { HttpClientTestingModule, HttpTestingController } from '../../../node_modules/@angular/common/http/testing';
import { environment } from '../../environments/environment';
import PAGES  from './mock-data/page.service.mock.spec';

fdescribe('PageService', () => {
  let pageSrv: PageService,
    httpTestingController: HttpTestingController;

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

    pageSrv = TestBed.get(PageService);
    httpTestingController = TestBed.get(HttpTestingController);
  });

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

  fit('should load page', fakeAsync(() => {
    const r = PAGES.NewsItem1
    pageSrv.loadPage('/news-announcements/article/announcement/');
    // flush();
    tick(5000);
    const req = httpTestingController.expectOne(environment.apiBaseURL + 'api/structure/page/');
    console.log('running expect');
    expect(req.request.method).toEqual("GET");

    req.flush({r});
  }));
});

Ответы [ 2 ]

1 голос
/ 25 октября 2019

Один из вариантов - , а не подписка в службе.

Вместо этого вы можете подписаться в компоненте ИЛИ использовать более декларативный, потоковый подход:

product.service.ts

@Injectable({
  providedIn: 'root'
})
export class ProductService {
  private productsUrl = 'api/products';

  // All products
  products$ = this.http.get<Product[]>(this.productsUrl)
    .pipe(
      tap(data => console.log('Products', JSON.stringify(data))),
      catchError(this.handleError)
    );
}

Кроме того, вот отличная статья, в которой предлагается два варианта тестирования наблюдаемых:

https://blog.angularindepth.com/how-to-test-observables-a00038c7faad

Наконец,Я не пробовал это, но вы можете использовать:

it('should...', async(async() => { } ))

Здесь есть пример: https://netbasal.com/testing-observables-in-angular-a2dbbfaf5329,, но он тестирует компонент с подпиской, а не сервис.

0 голосов
/ 25 октября 2019

Я согласен с DeborahK, что подписка на сервис вообще не очень хорошая идея. Тем не менее, это может быть код, для которого вас попросили написать тесты, но вы не можете его изменить, или вы просто хотите закодировать его таким образом, так что для прямого ответа на ваш вопрос все, что вам, вероятно, не хватает, - это то, что вы добавили запроспараметры вашего URL-адреса внутри метода обслуживания, но вы не учитываете это в выражении ожидаемого результата:

const req = httpTestingController.expectOne(environment.apiBaseURL + 'api/structure/page/');

Я собрал работающий StackBlitz , чтобы показать, что ваш тест сейчас проходити подписка вызывается. Вот полный fit() от этого StackBlitz:

fit('should load page', () => { // <--- do not need fakeAsync
  const r = PAGES.NewsItem1
  pageSrv.loadPage('/news-announcements/article/announcement/');
  // flush();
  // tick(5000);  // <--- This is not needed

  // build up the total expected URL including the query parameter added:
  const expectedURL = `${environment.apiBaseURL}api/structure/page/?path=/news-announcements/article/announcement//`

  const req = httpTestingController.expectOne(expectedURL);
  console.log('running expect');
  expect(req.request.method).toEqual("GET");
  req.flush({r});
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...