You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何利用firestore-mock测试Angular的Firestore数据库服务方法?

Testing AngularFirestore Methods with firestore-mock

Let's fix up your test setup and write proper test cases for your DatabaseService methods. First, we'll clean up the unnecessary parts in your spec file, then set up the mock correctly using firestore-mock to verify each method's behavior.

Step 1: Clean Up the Test File

First, remove imports that aren't relevant to testing DatabaseService (like LoginComponent, HttpClientTestingModule, etc.). We only need imports for Angular testing utilities, your service, and firestore-mock.

Step 2: Build a Proper AngularFirestore Mock

We'll create a mock AngularFirestore class that wraps the firestore-mock instance, so we can track method calls and validate interactions with Firestore.

Make sure you have @types/firebase installed for type support (if you don't already):

npm install --save-dev @types/firebase

Update your spec file's mock and TestBed configuration:

import { TestBed } from '@angular/core/testing';
import { DatabaseService } from './database.service';
import { AngularFirestore } from '@angular/fire/firestore';
import * as FirestoreMock from 'firestore-mock';

// Mock AngularFirestore to wrap firestore-mock functionality
class MockAngularFirestore {
  private firestoreInstance = new FirestoreMock();

  collection(subject: string) {
    const collectionRef = this.firestoreInstance.collection(subject);
    return {
      doc: (key: string) => {
        const docRef = collectionRef.doc(key);
        return {
          set: (data: any) => docRef.set(data),
          ref: {
            get: () => docRef.get()
          },
          delete: () => docRef.delete()
        };
      }
    };
  }

  // Expose the firestore instance for direct data checks
  get firestore() {
    return this.firestoreInstance;
  }
}

describe('DatabaseService', () => {
  let service: DatabaseService;
  let mockFirestore: MockAngularFirestore;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        DatabaseService,
        { provide: AngularFirestore, useClass: MockAngularFirestore }
      ]
    });

    service = TestBed.inject(DatabaseService);
    mockFirestore = TestBed.inject(AngularFirestore) as unknown as MockAngularFirestore;
  });

Step 3: Test pushToDatabase

We need to verify that the method calls Firestore's set() with the correctly serialized object.

describe('#pushToDatabase', () => {
    it('should serialize and save the object to the specified document', () => {
      // Arrange
      const testSubject = 'test-collection';
      const testKey = 'test-doc-id';
      const testObject = { name: 'Test Item', count: 42 };
      const serializedObject = JSON.parse(JSON.stringify(testObject));

      // Spy on Firestore methods to track calls
      const collectionSpy = spyOn(mockFirestore, 'collection').and.callThrough();
      const docSpy = spyOn(mockFirestore.collection(testSubject), 'doc').and.callThrough();
      const setSpy = spyOn(mockFirestore.collection(testSubject).doc(testKey), 'set');

      // Act
      service.pushToDatabase(testSubject, testKey, testObject);

      // Assert
      expect(collectionSpy).toHaveBeenCalledWith(testSubject);
      expect(docSpy).toHaveBeenCalledWith(testKey);
      expect(setSpy).toHaveBeenCalledWith(serializedObject);
    });
  });

Step 4: Test getData

For this async method, we'll pre-populate the mock Firestore with data, then verify the method returns the correct document data.

describe('#getData', () => {
    it('should fetch and return the document data', async () => {
      // Arrange
      const testSubject = 'test-collection';
      const testKey = 'test-doc-id';
      const testData = { name: 'Test Item', count: 42 };

      // Pre-populate mock Firestore with test data
      await mockFirestore.firestore.collection(testSubject).doc(testKey).set(testData);

      // Act
      const result = await service.getData(testSubject, testKey);

      // Assert
      expect(result).toEqual(testData);
      // Verify the get method was called
      const getSpy = spyOn(mockFirestore.collection(testSubject).doc(testKey).ref, 'get').and.callThrough();
      await service.getData(testSubject, testKey);
      expect(getSpy).toHaveBeenCalled();
    });
  });

Step 5: Test deleteData

We'll verify that the method deletes the specified document and that the document no longer exists in the mock Firestore.

describe('#deleteData', () => {
    it('should delete the specified document', async () => {
      // Arrange
      const testSubject = 'test-collection';
      const testKey = 'test-doc-id';
      const testData = { name: 'Test Item' };

      // Add a document to delete
      await mockFirestore.firestore.collection(testSubject).doc(testKey).set(testData);
      let preDeleteDoc = await mockFirestore.firestore.collection(testSubject).doc(testKey).get();
      expect(preDeleteDoc.exists).toBe(true);

      // Spy on the delete method
      const deleteSpy = spyOn(mockFirestore.collection(testSubject).doc(testKey), 'delete').and.callThrough();

      // Act
      await service.deleteData(testSubject, testKey);

      // Assert
      expect(deleteSpy).toHaveBeenCalled();
      const postDeleteDoc = await mockFirestore.firestore.collection(testSubject).doc(testKey).get();
      expect(postDeleteDoc.exists).toBe(false);
    });
  });
});

Key Tips

  • Use callThrough() on spies to ensure the mock's actual implementation runs (so we can validate side effects like data being added or deleted).
  • For async methods, always use async/await in test cases to handle promises correctly and avoid race conditions.
  • The mock exposes the firestore-mock instance directly, letting us pre-populate data and check document existence easily.

内容的提问来源于stack exchange,提问作者Kevin van Schaijk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:38:58