angular - Cum să testezi gestionarea erorilor componentelor cu serviciu observable


Context

Încerc să testez un component. Într-o altă postare am întrebat despre testarea apelului direct al funcției. Aici mă concentrez, folosind același component exemplu, pe gestionarea erorilor a componentului meu.

Vreau să testez, când serviciul meu returnează o eroare observabilă, că componenta mea apelează corect console.error(error).

Cum să "creezi" acest declanșator de eroare și să testezi dacă componenta mea îl gestionează corect. Am auzit că spionii ar putea face asta, dar nu știu unde să configurez acest spion.

Vreau să simulez cazul în care cererea http de pe serviciu ar putea eșua. Din orice motiv sau cod de eroare.

Cod

Iată codul pentru componentă, serviciul stub și fișierele mele spec.

Componentă

import { Component, OnInit, ViewContainerRef } from '@angular/core';

import { UserManagementService } from '../../shared/services/global.api';
import { UserListItemComponent } from './user-list-item.component';

@Component({
  selector: 'app-user-list',
  templateUrl: './user-list.component.html'
})
export class UserListComponent implements OnInit {
  public userList = [];

  constructor(
    private _userManagementService: UserManagementService,    
  ) { }

  ngOnInit() {
    this.getUserList();
  }

  onRefreshUserList() {
    this.getUserList();
  }

  getUserList(notifyWhenComplete = false) {
    this._userManagementService.getListUsers().subscribe(
      result => {
        this.userList = result.objects;
      },
      error => {
        console.error(error); // That's the part of my component I want to test     
      },
      () => {
        if (notifyWhenComplete) {
          console.info('Notification');
        }
      }
    );
  }
}

Fișier specificații componentă

import { NO_ERRORS_SCHEMA } from '@angular/core';
import {
  async,
  fakeAsync,
  ComponentFixture,
  TestBed,
  tick,
  inject
} from '@angular/core/testing';

import { Observable } from 'rxjs/Observable';

// Components
import { UserListComponent } from './user-list.component';

// Services
import { UserManagementService } from '../../shared/services/global.api';
import { UserManagementServiceStub } from '../../testing/services/global.api.stub';

let comp:    UserListComponent;
let fixture: ComponentFixture<UserListComponent>;
let service: UserManagementService;

describe('UserListComponent', () => {
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [UserListComponent],
      imports: [],
      providers: [
        {
          provide: UserManagementService,
          useClass: UserManagementServiceStub
        }
      ],
      schemas: [ NO_ERRORS_SCHEMA ]
    })
    .compileComponents();
  }));

  tests();
});

function tests() {
  beforeEach(() => {
    fixture = TestBed.createComponent(UserListComponent);
    comp = fixture.componentInstance;

    service = TestBed.get(UserManagementService);
  });

  it(`should be initialized`, () => {
    expect(fixture).toBeDefined();
    expect(comp).toBeDefined();
  });

  it(`should get the user List after ngOnInit`, async(() => {
    fixture.detectChanges();

    expect(comp.userList.length).toBe(3, 'user list exists after init');
  }));
}

Serviciu simulat

import { Observable } from 'rxjs/Observable';

export class UserManagementServiceStub {
  getListUsers() {
    return Observable.from([      
      {
        count: 3, 
        objects: 
        [
          {
            id: "7f5a6610-f59b-4cd7-b649-1ea3cf72347f",
            name: "user 1",
            group: "any"
          },
          {
            id: "d6f54c29-810e-43d8-8083-0712d1c412a3",
            name: "user 2",
            group: "any"
          },
          {
            id: "2874f506-009a-4af8-8ca5-f6e6ba1824cb", 
            name: "user 3",
            group: "any"
          }
        ]
      }
    ]);
  }
}

Răspuns #1

Dacă înțeleg corect că aveți nevoie doar de o modalitate de a returna o eroare dintr-un serviciu stub-uit, puteți pur și simplu să creați un stub separat care returnează o eroare Observable și apoi să-l folosiți în testul care verifică gestionarea erorilor:

export class UserManagementServiceErrorStub {
  getListUsers() {
    return Observable.throw(new Error('Test error'));
  }
}

Există un articol foarte bun despre testarea serviciilor Angular folosind Observables aici: https://web.archive.org/web/20191214083526/http://www.zackarychapple.guru/angular2/2016/11/25/angular2-testing-services.html

Actualizare - 01/06/2019 pentru RxJS 6

import { throwError } from 'rxjs'; 

class UserManagementServiceErrorStub {
  getListUsers() {
    return throwError(new Error('Test error'));
  }
}