294 lines
11 KiB
TypeScript
294 lines
11 KiB
TypeScript
import { Test, TestingModule } from '@nestjs/testing';
|
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
|
import { ConfigModule, ConfigService } from '@nestjs/config';
|
|
import { getRepositoryToken } from '@nestjs/typeorm';
|
|
import { Repository } from 'typeorm';
|
|
import { UserService } from '../../../src/modules/user/user.service';
|
|
import { User } from '../../../src/modules/user/user.entity';
|
|
import { UserModule } from '../../../src/modules/user/user.module';
|
|
import { CreateUserDto } from '../../../src/modules/user/dto/create-user.dto';
|
|
import { getDatabaseConfig } from '../../../src/database/database.config';
|
|
import { ConflictException } from '@nestjs/common';
|
|
|
|
describe('UserService (集成测试)', () => {
|
|
let service: UserService;
|
|
let repository: Repository<User>;
|
|
let module: TestingModule;
|
|
|
|
beforeAll(async () => {
|
|
jest.setTimeout(30000); // 设置超时为 30 秒
|
|
// 创建测试模块,使用真实数据库连接
|
|
module = await Test.createTestingModule({
|
|
imports: [
|
|
ConfigModule.forRoot({
|
|
isGlobal: true,
|
|
envFilePath: ['.env.development', '.env'],
|
|
}),
|
|
TypeOrmModule.forRootAsync({
|
|
imports: [ConfigModule],
|
|
useFactory: (configService: ConfigService) => {
|
|
const config = getDatabaseConfig(configService);
|
|
// 使用测试数据库(如果配置了),否则使用开发数据库
|
|
const testDatabase =
|
|
configService.get<string>('DB_DATABASE') ||
|
|
(config.database as string);
|
|
return {
|
|
...config,
|
|
database: testDatabase,
|
|
synchronize: true, // 测试环境允许同步
|
|
dropSchema: false, // 不删除现有数据
|
|
} as typeof config;
|
|
},
|
|
inject: [ConfigService],
|
|
}),
|
|
UserModule,
|
|
],
|
|
}).compile();
|
|
|
|
service = module.get<UserService>(UserService);
|
|
repository = module.get<Repository<User>>(getRepositoryToken(User));
|
|
|
|
// 清理测试数据(可选)
|
|
await repository.clear();
|
|
});
|
|
|
|
afterAll(async () => {
|
|
// 测试结束后清理
|
|
// await repository.clear();
|
|
await module.close();
|
|
});
|
|
|
|
describe('create - 集成测试', () => {
|
|
it('应该成功在数据库中创建用户', async () => {
|
|
const createUserDto: CreateUserDto = {
|
|
username: 'test_user_1',
|
|
password: 'password123',
|
|
email: 'test1@example.com',
|
|
nickname: '测试用户1',
|
|
};
|
|
|
|
const result = await service.create(createUserDto);
|
|
console.log('regitser result', result);
|
|
expect(result).toBeDefined();
|
|
expect(result.userId).toBeDefined();
|
|
expect(result.username).toBe(createUserDto.username);
|
|
expect(result.email).toBe(createUserDto.email);
|
|
expect(result.nickname).toBe(createUserDto.nickname);
|
|
expect(result.status).toBe('active');
|
|
expect(result.role).toBe('user'); // 默认角色
|
|
expect(result.passwordHash).toBeDefined();
|
|
expect(result.passwordHash).not.toBe(createUserDto.password); // 密码应该被加密
|
|
|
|
// 验证数据确实保存到数据库
|
|
const savedUser = await repository.findOne({
|
|
where: { userId: result.userId },
|
|
});
|
|
expect(savedUser).toBeDefined();
|
|
expect(savedUser?.username).toBe(createUserDto.username);
|
|
expect(savedUser?.email).toBe(createUserDto.email);
|
|
|
|
// 清理
|
|
await repository.remove(result);
|
|
});
|
|
|
|
it('应该使用默认角色和状态', async () => {
|
|
const createUserDto: CreateUserDto = {
|
|
username: 'test_user_2',
|
|
password: 'password123',
|
|
email: 'test2@example.com',
|
|
// 不提供 role
|
|
};
|
|
|
|
const result = await service.create(createUserDto);
|
|
|
|
expect(result.role).toBe('user'); // 默认角色
|
|
expect(result.status).toBe('active'); // 默认状态
|
|
|
|
// 清理
|
|
// await repository.remove(result);
|
|
});
|
|
|
|
it('应该支持可选字段', async () => {
|
|
const createUserDto: CreateUserDto = {
|
|
username: 'test_user_3',
|
|
password: 'password123',
|
|
email: 'test3@example.com',
|
|
nickname: '测试用户3',
|
|
avatarUrl: 'https://example.com/avatar.jpg',
|
|
phone: '13800138000',
|
|
};
|
|
|
|
const result = await service.create(createUserDto);
|
|
|
|
expect(result.nickname).toBe(createUserDto.nickname);
|
|
expect(result.avatarUrl).toBe(createUserDto.avatarUrl);
|
|
expect(result.phone).toBe(createUserDto.phone);
|
|
|
|
// 清理
|
|
// await repository.remove(result);
|
|
});
|
|
|
|
it('应该抛出 ConflictException 当用户名已存在时', async () => {
|
|
const createUserDto: CreateUserDto = {
|
|
username: 'duplicate_username',
|
|
password: 'password123',
|
|
email: 'unique@example.com',
|
|
};
|
|
|
|
// 先创建一个用户
|
|
await service.create(createUserDto);
|
|
|
|
// 尝试创建相同用户名的用户
|
|
const duplicateDto: CreateUserDto = {
|
|
username: 'duplicate_username',
|
|
password: 'password456',
|
|
email: 'another@example.com',
|
|
};
|
|
|
|
await expect(service.create(duplicateDto)).rejects.toThrow(
|
|
ConflictException,
|
|
);
|
|
await expect(service.create(duplicateDto)).rejects.toThrow(
|
|
'用户名',
|
|
);
|
|
|
|
// 清理
|
|
// const user = await repository.findOne({ where: { username: 'duplicate_username' } });
|
|
// if (user) await repository.remove(user);
|
|
});
|
|
|
|
it('应该抛出 ConflictException 当邮箱已存在时', async () => {
|
|
const createUserDto: CreateUserDto = {
|
|
username: 'unique_username',
|
|
password: 'password123',
|
|
email: 'duplicate@example.com',
|
|
};
|
|
|
|
// 先创建一个用户
|
|
await service.create(createUserDto);
|
|
|
|
// 尝试创建相同邮箱的用户
|
|
const duplicateDto: CreateUserDto = {
|
|
username: 'another_username',
|
|
password: 'password456',
|
|
email: 'duplicate@example.com',
|
|
};
|
|
|
|
await expect(service.create(duplicateDto)).rejects.toThrow(
|
|
ConflictException,
|
|
);
|
|
await expect(service.create(duplicateDto)).rejects.toThrow('邮箱');
|
|
|
|
// 清理
|
|
// const user = await repository.findOne({ where: { email: 'duplicate@example.com' } });
|
|
// if (user) await repository.remove(user);
|
|
});
|
|
});
|
|
|
|
describe('findAll - 集成测试', () => {
|
|
it('应该返回所有用户列表', async () => {
|
|
// 先创建几个测试用户
|
|
const users: CreateUserDto[] = [
|
|
{
|
|
username: 'findall_user_1',
|
|
password: 'password123',
|
|
email: 'findall1@example.com',
|
|
nickname: '查询测试用户1',
|
|
},
|
|
{
|
|
username: 'findall_user_2',
|
|
password: 'password123',
|
|
email: 'findall2@example.com',
|
|
nickname: '查询测试用户2',
|
|
},
|
|
{
|
|
username: 'findall_user_3',
|
|
password: 'password123',
|
|
email: 'findall3@example.com',
|
|
nickname: '查询测试用户3',
|
|
role: 'admin',
|
|
},
|
|
];
|
|
|
|
const createdUsers: User[] = [];
|
|
for (const userDto of users) {
|
|
const user = await service.create(userDto);
|
|
createdUsers.push(user);
|
|
}
|
|
|
|
// 查询所有用户
|
|
const result = await service.findAll();
|
|
|
|
expect(result).toBeDefined();
|
|
expect(Array.isArray(result)).toBe(true);
|
|
expect(result.length).toBeGreaterThanOrEqual(users.length);
|
|
|
|
// 验证创建的用户都在列表中
|
|
const usernames = result.map((u) => u.username);
|
|
users.forEach((userDto) => {
|
|
expect(usernames).toContain(userDto.username);
|
|
});
|
|
|
|
// 验证排序(按创建时间倒序)
|
|
if (result.length > 1) {
|
|
for (let i = 0; i < result.length - 1; i++) {
|
|
expect(
|
|
result[i].createdAt.getTime(),
|
|
).toBeGreaterThanOrEqual(result[i + 1].createdAt.getTime());
|
|
}
|
|
}
|
|
|
|
// 清理
|
|
// await repository.remove(createdUsers);
|
|
});
|
|
|
|
it('应该返回空数组当没有用户时', async () => {
|
|
// 清理所有用户
|
|
await repository.clear();
|
|
|
|
const result = await service.findAll();
|
|
|
|
expect(result).toBeDefined();
|
|
expect(Array.isArray(result)).toBe(true);
|
|
expect(result.length).toBe(0);
|
|
});
|
|
|
|
it('应该包含用户的所有字段', async () => {
|
|
// 创建一个完整信息的用户
|
|
const createUserDto: CreateUserDto = {
|
|
username: 'full_info_user',
|
|
password: 'password123',
|
|
email: 'fullinfo@example.com',
|
|
nickname: '完整信息用户',
|
|
avatarUrl: 'https://example.com/avatar.jpg',
|
|
phone: '13800138000',
|
|
role: 'admin',
|
|
};
|
|
|
|
await service.create(createUserDto);
|
|
|
|
// 查询所有用户
|
|
const result = await service.findAll();
|
|
|
|
const foundUser = result.find(
|
|
(u) => u.username === createUserDto.username,
|
|
);
|
|
|
|
expect(foundUser).toBeDefined();
|
|
expect(foundUser?.userId).toBeDefined();
|
|
expect(foundUser?.username).toBe(createUserDto.username);
|
|
expect(foundUser?.email).toBe(createUserDto.email);
|
|
expect(foundUser?.nickname).toBe(createUserDto.nickname);
|
|
expect(foundUser?.avatarUrl).toBe(createUserDto.avatarUrl);
|
|
expect(foundUser?.phone).toBe(createUserDto.phone);
|
|
expect(foundUser?.role).toBe(createUserDto.role);
|
|
expect(foundUser?.status).toBe('active');
|
|
expect(foundUser?.createdAt).toBeDefined();
|
|
expect(foundUser?.updatedAt).toBeDefined();
|
|
|
|
// 清理
|
|
// if (foundUser) await repository.remove(foundUser);
|
|
});
|
|
});
|
|
});
|