Как проверить сервис, который взаимодействует с Firebase?

Похоже, что соглашение для сбора данных из Firebase заключается в создании класса обслуживания, который использует AngularFire для внутреннего использования. Затем в компонентах вашего приложения вы можете внедрить и использовать сервис. Это позволяет легко смоделировать сервис при модульном тестировании ваших компонентов.

Но я до сих пор не понимаю, как проводить тестирование самого сервиса.

В качестве примера, скажем, у меня есть todo list узел в Firebase, и у меня есть простой сервис, который захватывает все todos, вот так:

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');
  }
}

Как вы будете проверять, что этот сервис выполняет то, что вы ожидаете?

2 ответа

Решение

Реаз порекомендовал MockFirebase в своем ответе. Однако MockFirebase не работает с Firebase 3. Существует библиотека под названием firebase-mock, которая, похоже, разработана некоторыми из тех же людей, что и MockFirebase. Это расширяет возможности MF, добавляя поддержку Firebase 3, однако , похоже, с WebPack он пока не работает.

Вот что я в итоге сделал:

Мне пришло в голову, что FirebaseListObservable наследует от RXJS Observable, Таким образом, вы можете просто смоделировать вызов AngularFire list и пусть он вернет ваш собственный наблюдаемый.

Пример кода, показывающий это в действии:

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) {}
}

Вопрос в основном основан на мнении, и поэтому я просто высказываю свое мнение здесь.

Я бы создал тестовый узел в Firebase, имеющий точно такую ​​же модель моей базы данных разработки. Поэтому при написании модульного теста я вставлял некоторые данные и извлекал их снова, чтобы они соответствовали данным, которые я вставил ранее.

По сути, Firebase хранит данные в структуре Json. Поэтому я бы написал несколько тестовых записей Json todo. Я не буду издеваться над эталонным объектом Firebase или подключением, поскольку это в основном стороннее программное обеспечение. Я бы установил реальное соединение с Firebase во время выполнения модульного теста, вставил некоторые данные и получил их обратно и сопоставил бы с данными, которые я вставил ранее. Это был бы мой подход.

Обновить

Да, у вас есть действительные опасения относительно непрерывной интеграции Честно говоря, я не делал ничего подобного раньше с командой и CI-сервером. Я не могу гарантировать гладкий опыт.

В поисках лучшего решения я нашел MockFirebase, который мог бы служить вашей цели. Вы можете посмотреть.

Я хотел бы сослаться на этот ответ, где он предложил хранить вызовы Firebase в библиотеке. Хотя это не относится к CI-серверу.

Другие вопросы по тегам