user.service.test.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. import { UserService } from '../../../../src/server/modules/users/user.service';
  2. import { UserEntity as User } from '../../../../src/server/modules/users/user.entity';
  3. import * as bcrypt from 'bcrypt';
  4. import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
  5. // Mock TypeORM 数据源和仓库
  6. vi.mock('typeorm', async (importOriginal) => {
  7. const actual = await importOriginal() as any
  8. return {
  9. ...actual,
  10. DataSource: vi.fn().mockImplementation(() => ({
  11. getRepository: vi.fn()
  12. })),
  13. Repository: vi.fn()
  14. }
  15. });
  16. // Mock bcrypt
  17. vi.mock('bcrypt', () => ({
  18. hash: vi.fn().mockResolvedValue('hashed_password'),
  19. compare: vi.fn().mockResolvedValue(true)
  20. }));
  21. describe('UserService', () => {
  22. let userService: UserService;
  23. let mockDataSource: any;
  24. let mockUserRepository: any;
  25. let mockRoleRepository: any;
  26. beforeEach(() => {
  27. // 创建模拟的仓库实例
  28. mockUserRepository = {
  29. create: vi.fn(),
  30. save: vi.fn(),
  31. findOne: vi.fn(),
  32. update: vi.fn(),
  33. delete: vi.fn(),
  34. createQueryBuilder: vi.fn(),
  35. find: vi.fn(),
  36. findByIds: vi.fn()
  37. } as any;
  38. mockRoleRepository = {
  39. findByIds: vi.fn()
  40. } as any;
  41. // 创建模拟的数据源
  42. mockDataSource = {
  43. getRepository: vi.fn()
  44. } as any;
  45. // 设置数据源返回模拟的仓库
  46. mockDataSource.getRepository
  47. .mockReturnValueOnce(mockUserRepository)
  48. .mockReturnValueOnce(mockRoleRepository);
  49. userService = new UserService(mockDataSource);
  50. });
  51. afterEach(() => {
  52. vi.clearAllMocks();
  53. });
  54. describe('createUser', () => {
  55. it('应该成功创建用户并哈希密码', async () => {
  56. const userData = {
  57. username: 'testuser',
  58. password: 'password123',
  59. email: 'test@example.com'
  60. };
  61. const mockUser = { id: 1, ...userData, password: 'hashed_password' } as User;
  62. mockUserRepository.create.mockReturnValue(mockUser);
  63. mockUserRepository.save.mockResolvedValue(mockUser);
  64. const result = await userService.createUser(userData);
  65. expect(bcrypt.hash).toHaveBeenCalledWith('password123', 10);
  66. expect(mockUserRepository.create).toHaveBeenCalledWith({
  67. ...userData,
  68. password: 'hashed_password'
  69. });
  70. expect(mockUserRepository.save).toHaveBeenCalledWith(mockUser);
  71. expect(result).toEqual(mockUser);
  72. });
  73. it('应该在创建用户失败时抛出错误', async () => {
  74. const userData = { username: 'testuser', password: 'password123' };
  75. const error = new Error('Database error');
  76. mockUserRepository.create.mockImplementation(() => {
  77. throw error;
  78. });
  79. await expect(userService.createUser(userData)).rejects.toThrow('Failed to create user');
  80. });
  81. });
  82. describe('getUserById', () => {
  83. it('应该通过ID成功获取用户', async () => {
  84. const mockUser = { id: 1, username: 'testuser' } as User;
  85. mockUserRepository.findOne.mockResolvedValue(mockUser);
  86. const result = await userService.getUserById(1);
  87. expect(mockUserRepository.findOne).toHaveBeenCalledWith({
  88. where: { id: 1 },
  89. relations: ['roles', 'avatarFile']
  90. });
  91. expect(result).toEqual(mockUser);
  92. });
  93. it('应该在用户不存在时返回null', async () => {
  94. mockUserRepository.findOne.mockResolvedValue(null);
  95. const result = await userService.getUserById(999);
  96. expect(result).toBeNull();
  97. });
  98. });
  99. // getUsersWithPagination 方法已移除,使用通用CRUD服务替代
  100. describe('verifyPassword', () => {
  101. it('应该验证密码正确', async () => {
  102. const user = { password: 'hashed_password' } as User;
  103. const result = await userService.verifyPassword(user, 'password123');
  104. expect(bcrypt.compare).toHaveBeenCalledWith('password123', 'hashed_password');
  105. expect(result).toBe(true);
  106. });
  107. it('应该验证密码错误', async () => {
  108. (vi.mocked(bcrypt.compare) as any).mockResolvedValueOnce(false);
  109. const user = { password: 'hashed_password' } as User;
  110. const result = await userService.verifyPassword(user, 'wrong_password');
  111. expect(result).toBe(false);
  112. });
  113. });
  114. });