Раньше я писал несколько сообщений, используя Firebase и библиотеку AngularFire2. Библиотека AngularFire2 делает использование и интеграцию Firebase с вашими приложениями Angular очень увлекательным и простым занятием.
AngularFire2 также позволяет создавать приложения JAMStack, для которых требуется только интерфейс и вызовы различных служб Firebase (Auth, Database и т. Д.). После ознакомления с документацией по AngularFire2 README вы можете довольно легко приступить к работе. Оттуда просто нужно внедрить различные сервисы в ваши компоненты Angular.
Недавно я создал приложение Angular, которое использует AngularFire2. Приложение также использует Jest для модульного тестирования. Я узнал кое-что в процессе его создания и хотел поделиться для дальнейшего использования.
В этом посте я расскажу о моем приложении и некоторых основах настройки Jest. Я не собираюсь описывать начальную настройку AngularFire2, поскольку ее репозиторий на GitHub охватывает ее. Я также не собираюсь много говорить об интеграции Jest с Angular, за исключением того, что использую Angular Builder для Jest вместо Karma. Строители великолепны, поскольку позволяют использовать Angular CLI. Я кратко расскажу об этом, а также об использовании Jest в первом разделе.
Рестораны ReyRey’s
Приложение, о котором я расскажу, называется ReyRey’s Restaurants. Вы можете добраться до него, перейдя на https://www.reyreysrestaurants.com. Приложение представляет собой интересный способ отслеживать рестораны, которые вы посещаете в своем городе. Проект построен и размещен на Firebase и построен на AngularFire2 для подключения к службам аутентификации и баз данных. Я сделал его с открытым исходным кодом, и вы можете посмотреть исходный код на GitHub здесь.
Кроме того, я создал приложение, чтобы получить интересный способ отслеживать рестораны в моем городе и включить мою кошку (Рей) в один из моих проектов. У меня уже есть Chessie Choochoo для другого моего кота (Chestnut), поэтому я не хотел упускать из виду Рей (см. Https://www.chessiechoochoo.com).
Я установил некоторые документы, чтобы вы могли легко увидеть, как использовать приложение здесь. Основная предпосылка заключается в том, что вы создаете учетную запись, а затем добавляете рестораны в раздел Хочу пойти. Когда вы посещаете свой ресторан, вы можете продвигать его как был там и добавлять отзывы с комментариями, звездами и т. Д. Вот несколько скриншотов:
Настройка проекта
Как я уже упоминал в начале, двумя важными вещами в этом проекте были AngularFire2 и Jest.
Я не буду вдаваться в подробности, как настроить AngularFire2 с вашим проектом, поскольку README в их репозитории в значительной степени покрывает это. Я, тем не менее, порекомендую вам мой пост Как библиотека AngularFire делает Firebase похожим на Magic, поскольку в нем есть хороший набор инструкций для начала.
Для настройки Jest с вашим проектом есть несколько способов сделать это. Я обнаружил, что использование Jest Builder было для меня самым простым вариантом. Помимо инструкций в README, я также сделал следующее:
Самое интересное в использовании компоновщика заключалось в том, что я смог использовать существующий интерфейс командной строки Angular для выполнения этой работы. Таким образом, каждый раз, когда я звонил «ng test», он запускал средство выполнения тестов Jest, а не средство выполнения Karma, которое обычно используется по умолчанию.
Поиграв с ним, я должен сказать, что мне очень понравился Jest по следующим причинам:
- Сообщения об ошибках и предупреждения легко понять.
- Средство выполнения тестов дает вам более детальные параметры
Я не собираюсь вдаваться в подробности о Jest, потому что несколько других людей очень хорошо это осветили. Рекомендую прочитать пост Angular CLI:« ng test с Jest за 3 минуты (v2)». Также (хотя в статье не используются компоновщики) я рекомендую ознакомиться со статьей Интеграция Jest в приложение и библиотеку Angular, чтобы узнать больше о Jest с Angular. Наконец, Jest Getting Started Docs - отличное место, где можно найти примеры и более подробную информацию.
Тестирование Angularfire2 с помощью Jest
Обычно модульное тестирование библиотек с различными службами было довольно простым. Вы имитируете зависимости, которые вам нужно внедрить, и используете различные хуки (beforeEach, afterEach и т. Д.) Для обработки данных, которые вы тестируете.
С AngularFire2 у меня возник ряд проблем, пытаясь имитировать различные библиотеки из-за различных методов, которые мне нужно было обрабатывать для моих компонентов и т. Д. Это не было задокументировано так, как я надеялся, и потребовало довольно обширного поиска в Google. К счастью, я обнаружил проблему с GitHub здесь, в которой обсуждается добавление документации по тестированию в репозиторий проекта. В этом выпуске GitHub у этого ответа был отличный пример, который помог мне узнать, как это сделать для моего проекта.
В качестве небольшого отказа от ответственности, прежде чем я перейду к своим тестам, я хочу отметить, что есть еще много тестов, которые можно добавить. На момент написания этой статьи временные ограничения ограничили то, сколько я могу добавить. Я создал успешный набор тестов для классов обслуживания в моем проекте. Установку, которую я использовал для этих тестов, можно использовать и для компонентов, которые от них зависят.
Я написал набор классов обслуживания, которые выделяют сервисы AngularFire2 в свои собственные классы. Это упростило задачу, потому что тогда у меня было больше гибкости в именовании и в том, как я хотел использовать AngularFire2.
Основной процесс тестирования этих сервисов - создать заглушку и имитировать значения для методов библиотеки AngularFire2. Эти фиктивные значения фактически имитируют реальные значения, которые будут возвращены из методов службы Firebase.
Для Службы аутентификации у меня следующие настройки:
const credentialsMock = { email: '[email protected]', password: 'password' }; const userMock = { uid: 'ABC123', email: credentialsMock.email }; const createUserMock = { user: { uid: 'ABC123', email: credentialsMock.email } }; const fakeAuthState = new BehaviorSubject(null); const fakeSignInHandler = (email, password): Promise<any> => { fakeAuthState.next(userMock); return Promise.resolve(userMock); }; const fakeCreateUserHandler = (email, password): Promise<any> => { fakeAuthState.next(createUserMock); return Promise.resolve(createUserMock); }; const fakeSignOutHandler = (): Promise<any> => { fakeAuthState.next(null); return Promise.resolve(); }; const angularFireAuthStub = { authState: fakeAuthState, auth: { createUserWithEmailAndPassword: (email: string, password: string) => fakeCreateUserHandler(email, password), signInWithEmailAndPassword: (email: string, password: string) => fakeSignInHandler(email, password), signOut: () => fakeSignOutHandler() } };
Затем в моем фактическом тестовом блоке describe
я ссылаюсь на значение angularFireAuthStub
здесь:
describe('AuthenticationService', () => { let service: AuthenticationService; let afAuth: AngularFireAuth; beforeEach(() => { TestBed.configureTestingModule({ providers: [{ provide: AngularFireAuth, useValue: angularFireAuthStub }] }); service = TestBed.get(AuthenticationService); afAuth = TestBed.get(AngularFireAuth); }); afterEach(() => { fakeAuthState.next(null); });
Затем в самих тестах я просто вызываю свои методы обслуживания и проверяю ответы на макеты и заглушки:
test('should call the create user with email and password successfully', async () => { const response = await service.createUserWithEmailAndPassword( credentialsMock.email, credentialsMock.password ); expect(response).toBe(createUserMock.user.uid); });
После того, как у меня была запущена и запущена служба аутентификации, я построил тесты для службы базы данных. Настройка была похожа на службу аутентификации и имела следующее:
let service: DatabaseService; let savedValues = []; const user = { uid: 'ABC123', firstName: 'first', lastName: 'last', email: '[email protected]' }; const wgRestaurant: WgRestaurant = { id: '1234', uid: 'abc123', name: 'name', link: 'link', description: 'description', recorded: 1234 }; const btRestaurant: BtRestaurant = { id: '1234', uid: '5678', name: 'restaurant name', description: 'restaurant description', location: 'restaurant location', link: 'restaurant link', stars: 5, review: 'restaurant review', recorded: 1234 }; const fakeAddValueHandler = (value: any): Promise<any> => { return Promise.resolve(savedValues.push(value)); }; const deleteAddedValueHandler = (): Promise<any> => { return Promise.resolve((savedValues = [])); }; const firestoreStub = { collection: (name: string) => ({ doc: (id: string) => ({ valueChanges: () => new BehaviorSubject({ foo: 'bar' }), set: (d: any) => fakeAddValueHandler(d) }) }), createId: () => { return new Promise((resolve, reject) => resolve('1234567890')); }, doc: (idFirst: string) => ({ collection: (name: string) => ({ doc: (idSecond: string) => ({ valueChanges: () => new BehaviorSubject({ foo: 'bar' }), set: (d: any) => fakeAddValueHandler(d), delete: () => deleteAddedValueHandler() }) }) }) };
Если вы заметили, я обычно использую массив всякий раз, когда значения сохраняются в базе данных Cloud Firestore. Очевидно, это нужно настроить для более детального тестирования. Я был очень озабочен базовым вызовом различных методов, поэтому оставил все как есть.
Я использовал beforeEach
и afterEach
для настройки тестов, как вы видите здесь:
beforeEach(() => { TestBed.configureTestingModule({ providers: [{ provide: AngularFirestore, useValue: firestoreStub }] }); service = TestBed.get(DatabaseService); }); // clear out any saved values afterEach(() => (savedValues = []));
Затем, наконец, когда тесты действительно вызываются, вы просто вызываете методы службы и проверяете значения заглушки и фиктивного значения:
test('should call add user successfully', async () => { await service.addUser(user); expect(savedValues.length).toEqual(1); });
У меня большой опыт работы с Karma, поэтому я впервые по-настоящему играл с Jest. В целом я нашел его очень интуитивно понятным, и с ним было довольно легко работать. В частности, мне понравились предупреждения и сообщения, которые мне давал CLI. Они действительно помогли мне отработать то, что мне нужно для нормальной конфигурации, построения тестов и т. Д.
Заключительные мысли
Надеюсь, вам понравился этот пост, и вы тоже кое-что из него узнали. Мне очень нравится использовать AngularFire2 в моих проектах, потому что он позволяет легко интегрировать Firebase в приложения Angular. Также было здорово использовать Jest для модульного тестирования вместо Karma, как я всегда делал раньше. Мой проект здесь действительно охватывает лишь некоторые основы, и вы можете сделать гораздо больше как с AngularFire2, так и с Jest. Также я надеюсь, что вы заглянули в ReyRey’s Restaurants и, возможно, даже используете его, когда проверяете местные рестораны!
Спасибо за чтение! Следуйте за мной в Твиттере на @ AndrewEvans0102!
Первоначально опубликовано на https://rhythmandbinary.com 6 января 2020 г.