如何创建含lastRefreshTime的用户,测试Firebase非活跃用户清理云函数?
解决Firebase清理非活跃用户云函数的测试问题
问题背景
你开发了一个每24小时执行的云函数,用于删除metadata.lastRefreshTime为null的非活跃用户,但测试时无法通过createUser自定义该字段,导致无法验证函数逻辑。
可行解决方案
方案1:Mock Firebase Auth服务(推荐)
不依赖真实Firebase Auth实例,直接Mock核心方法,预设测试用的用户数据,专注验证函数的业务逻辑:
import { cleanInactiveAccount } from '../src/functions'; import * as admin from 'firebase-admin'; jest.mock('firebase-admin', () => { const mockAuth = { listUsers: jest.fn(), deleteUsers: jest.fn().mockResolvedValue({ successCount: 1, failureCount: 0 }) }; return { auth: jest.fn().mockReturnValue(mockAuth), initializeApp: jest.fn() }; }); describe('cleanInactiveAccount', () => { it('should delete users with null lastRefreshTime', async () => { // 预设模拟用户列表:1个非活跃用户,1个活跃用户 const mockListUsersResult = { users: [ { uid: 'inactive-user', metadata: { lastRefreshTime: null } }, { uid: 'active-user', metadata: { lastRefreshTime: new Date().toISOString() } } ], pageToken: null }; (admin.auth().listUsers as jest.Mock).mockResolvedValue(mockListUsersResult); const wrapped = wrap(cleanInactiveAccount); const result = await wrapped(); expect(result).toEqual('Successful'); // 验证仅删除了非活跃用户 expect(admin.auth().deleteUsers).toHaveBeenCalledWith(['inactive-user']); }); });
方案2:利用真实Auth实例的默认行为
新创建的Firebase用户默认lastRefreshTime为null(未触发过登录、token刷新等操作),可直接基于此特性测试:
test('cleanInactiveAccount deletes newly created inactive users', async () => { // 创建未登录过的非活跃用户(lastRefreshTime默认null) const inactiveUser = await defaultAuth.createUser({ email: 'test-inactive@example.com' }); // 创建活跃用户并模拟登录行为(触发lastRefreshTime更新) const activeUser = await defaultAuth.createUser({ email: 'test-active@example.com' }); await defaultAuth.setCustomUserClaims(activeUser.uid, { lastLogin: new Date().toISOString() }); const wrapped = wrap(functions.cleanInactiveAccount); await expect(wrapped()).resolves.toEqual('Successful'); // 验证非活跃用户已被删除 await expect(defaultAuth.getUser(inactiveUser.uid)).rejects.toThrow(); // 验证活跃用户仍存在 await expect(defaultAuth.getUser(activeUser.uid)).resolves.toBeDefined(); });
额外优化建议
- 生产环境中,
listAllUsers的递归逻辑可改用循环实现,避免超大用户量下的栈溢出问题 - 测试结束后清理测试用户,避免残留数据:
afterAll(async () => { const users = await defaultAuth.listUsers(); await Promise.all(users.users.map(user => defaultAuth.deleteUser(user.uid))); });
内容的提问来源于stack exchange,提问作者flutroid
相关产品推荐
相关产品推荐

