Parece que la convención para obtener datos de Firebase es crear una clase de servicio que use AngularFire internamente. Luego, en los componentes de su aplicación, puede inyectar y usar el servicio. Esto le permite simular fácilmente el servicio cuando la unidad prueba sus componentes.

Pero todavía no tengo claro cómo probar el servicio real en sí.

Como ejemplo, digamos que tengo un nodo todo list en Firebase y tengo un servicio simple que toma todos los todos, así:

import { Injectable } from '@angular/core';
import { AngularFire } from 'angularfire2';

@Injectable()
export class TodoService {
  constructor(private af: AngularFire) { }

  getAll(): FirebaseListObservable<any[]> {
    return this.af.database.list('todos');
  }
}

¿Cómo haría para probar que este servicio hace lo que espera?

4
Elliot Larson 13 dic. 2016 a las 21:04

2 respuestas

La mejor respuesta

Reaz recomendó MockFirebase en su respuesta. Sin embargo, MockFirebase no funciona con Firebase 3. Existe una biblioteca llamada firebase-mock, que parece haber sido desarrollada por algunas de las mismas personas que MockFirebase. Esto aumenta MF, agregando compatibilidad con Firebase 3, sin embargo, no parece funcionar bien con WebPack todavía.

Esto es lo que terminé haciendo:

Se me ocurrió que FirebaseListObservable hereda de Observable de RXJS. Por lo tanto, puede simular la llamada de AngularFire a list y hacer que devuelva su propio Observable.

Algún código de ejemplo que muestra esto en acción:

todos.service.spec.ts

let fixtureTodos = [
  { 'text': 'Get milk' },
  { 'text': 'Take out the trash' },
  { 'text': 'Get gas for the car' },
  { 'text': 'Pay parking ticket' },
  { 'text': 'Pick up dry cleaning' },
];
let angularFireDatabaseStub = { list: () => {} };
let mockTodos$ = Observable.of(fixtureTodos);

describe('TodosService', () => {
  beforeEach(() => {
    spyOn(angularFireDatabaseStub, 'list').and.returnValue(mockTodos$);

    TestBed.configureTestingModule({
      providers: [
        TodosService,
        { provide: AngularFireDatabase, useValue: angularFireDatabaseStub },
      ]
    });
  });

  it('#getAll', inject([TodosService], (service: TodosService) => {
    let todos$ = service.getAll();
    todos$.subscribe(todos => {
      expect(todos[0].text).toEqual(fixtureTodos[0].text);
      expect(todos[0]).toEqual(jasmine.any(Todo));
    });
  }));
});

todos.service.ts

@Injectable()
export class TodosService {
  constructor(public db: AngularFireDatabase) { }

  getAll(): Observable<Todo[]> {
    return this.db.list('todos').map(arr => {
      return arr.map(t => new Todo(t.text));
    });
  }
}

todo.model.ts

export class Todo {
  constructor(public text: string) {}
}
7
Elliot Larson 5 ene. 2017 a las 16:50

La pregunta se basa principalmente en opiniones y, por lo tanto, solo estoy poniendo mi opinión aquí.

Crearía un nodo de prueba en Firebase con exactamente el mismo modelo de mi base de datos de desarrollo. Entonces, mientras escribía la prueba unitaria, insertaría algunos datos y los recuperaría nuevamente para que coincidan con los datos que inserté antes.

Básicamente, Firebase almacena datos en una estructura Json. Así que escribiría algunas entradas de prueba de Json todo. No me burlaré del objeto de referencia de Firebase o la conexión, ya que este es básicamente el software de terceros. Haría una conexión real con Firebase mientras ejecutaba la prueba unitaria, insertaba algunos datos y los recuperaba y los combinaba con los datos que he insertado antes. Ese sería mi enfoque.

Actualizar

Sí, tiene algunas preocupaciones válidas con respecto a la integración continua. Honestamente, no había hecho algo como esto antes con un equipo y un servidor de CI. No puedo garantizar una experiencia fluida.

Mientras buscaba una solución mejor, encontré MockFirebase que podría servir para su propósito. Puedes echar un vistazo.

Me gustaría referirme a esta respuesta, donde sugirió mantener las llamadas de Firebase en una biblioteca. Sin embargo, esto no considera el servidor CI.

1
Community 23 may. 2017 a las 12:34