feat: 开发broker相关代码,开发全局代码
This commit is contained in:
240
apps/api/test/modules/broker/broker.e2e-spec.ts
Normal file
240
apps/api/test/modules/broker/broker.e2e-spec.ts
Normal file
@@ -0,0 +1,240 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import request from 'supertest';
|
||||
import { AppModule } from '../../../src/app.module';
|
||||
import { Broker } from '../../../src/modules/broker/broker.entity';
|
||||
import { Response } from '../../../src/common/interceptors/transform.interceptor';
|
||||
|
||||
describe('BrokerController (e2e)', () => {
|
||||
let app: INestApplication;
|
||||
|
||||
beforeAll(async () => {
|
||||
jest.setTimeout(30000);
|
||||
const moduleFixture: TestingModule = await Test.createTestingModule({
|
||||
imports: [AppModule], // 导入整个应用模块
|
||||
}).compile();
|
||||
|
||||
app = moduleFixture.createNestApplication();
|
||||
await app.init(); // 初始化应用(包括所有中间件、管道、拦截器等)
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await app.close();
|
||||
});
|
||||
|
||||
describe('POST /api/broker', () => {
|
||||
it('应该成功创建券商(完整流程)', () => {
|
||||
return request(app.getHttpServer())
|
||||
.post('/api/broker')
|
||||
.send({
|
||||
brokerCode: 'E2E_TEST',
|
||||
brokerName: 'E2E测试券商',
|
||||
region: 'CN',
|
||||
sortOrder: 1,
|
||||
isActive: true,
|
||||
})
|
||||
.expect(201)
|
||||
.expect((res) => {
|
||||
// 验证响应格式(经过 TransformInterceptor 处理)
|
||||
expect(res.body).toHaveProperty('code', 0);
|
||||
expect(res.body).toHaveProperty('message', 'success');
|
||||
expect(res.body).toHaveProperty('data');
|
||||
expect(res.body.data).toHaveProperty(
|
||||
'brokerCode',
|
||||
'E2E_TEST',
|
||||
);
|
||||
expect(res.body.data).toHaveProperty(
|
||||
'brokerName',
|
||||
'E2E测试券商',
|
||||
);
|
||||
expect(res.body.data).toHaveProperty('brokerId');
|
||||
});
|
||||
});
|
||||
|
||||
it('应该返回 400 当数据验证失败时', () => {
|
||||
return request(app.getHttpServer())
|
||||
.post('/api/broker')
|
||||
.send({
|
||||
// 缺少必需字段
|
||||
brokerCode: 'TEST',
|
||||
})
|
||||
.expect(400)
|
||||
.expect((res) => {
|
||||
// 验证错误响应格式(经过 HttpExceptionFilter 处理)
|
||||
expect(res.body).toHaveProperty('code');
|
||||
expect(res.body).toHaveProperty('message');
|
||||
expect(res.body.code).not.toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
it('应该返回 409 当券商代码已存在时', async () => {
|
||||
// 先创建一个券商
|
||||
await request(app.getHttpServer())
|
||||
.post('/api/broker')
|
||||
.send({
|
||||
brokerCode: 'DUPLICATE_TEST',
|
||||
brokerName: '重复测试',
|
||||
region: 'CN',
|
||||
})
|
||||
.expect(201);
|
||||
|
||||
// 尝试创建重复的券商
|
||||
return request(app.getHttpServer())
|
||||
.post('/api/broker')
|
||||
.send({
|
||||
brokerCode: 'DUPLICATE_TEST',
|
||||
brokerName: '重复测试2',
|
||||
region: 'CN',
|
||||
})
|
||||
.expect(409)
|
||||
.expect((res) => {
|
||||
expect(res.body.code).toBe(409);
|
||||
expect(res.body.message).toContain('already exists');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET /api/broker', () => {
|
||||
it('应该返回券商列表', async () => {
|
||||
// 先创建一个券商
|
||||
const createResponse = await request(app.getHttpServer())
|
||||
.post('/api/broker')
|
||||
.send({
|
||||
brokerCode: 'GET_TEST',
|
||||
brokerName: '查询测试',
|
||||
region: 'CN',
|
||||
})
|
||||
.expect(201);
|
||||
|
||||
// 查询券商列表
|
||||
return request(app.getHttpServer())
|
||||
.get('/api/broker')
|
||||
.expect(200)
|
||||
.expect((res) => {
|
||||
expect(res.body).toHaveProperty('code', 0);
|
||||
expect(res.body).toHaveProperty('data');
|
||||
expect(Array.isArray(res.body.data)).toBe(true);
|
||||
// 验证创建的券商在列表中
|
||||
const found = res.body.data.find(
|
||||
(b: { brokerCode: string }) =>
|
||||
b.brokerCode === 'GET_TEST',
|
||||
);
|
||||
expect(found).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it('应该支持按条件查询', async () => {
|
||||
// 先创建一个券商
|
||||
await request(app.getHttpServer())
|
||||
.post('/api/broker')
|
||||
.send({
|
||||
brokerCode: 'QUERY_TEST',
|
||||
brokerName: '条件查询测试',
|
||||
region: 'CN',
|
||||
})
|
||||
.expect(201);
|
||||
|
||||
// 按 brokerCode 查询
|
||||
return request(app.getHttpServer())
|
||||
.get('/api/broker?brokerCode=QUERY_TEST')
|
||||
.expect(200)
|
||||
.expect((res) => {
|
||||
expect(res.body.code).toBe(0);
|
||||
expect(res.body.data).toHaveLength(1);
|
||||
expect(res.body.data[0].brokerCode).toBe('QUERY_TEST');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET /api/broker/:id', () => {
|
||||
it('应该返回单个券商', async () => {
|
||||
// 先创建一个券商
|
||||
const createResponse = await request(app.getHttpServer())
|
||||
.post('/api/broker')
|
||||
.send({
|
||||
brokerCode: 'GET_ONE_TEST',
|
||||
brokerName: '单个查询测试',
|
||||
region: 'CN',
|
||||
})
|
||||
.expect(201);
|
||||
|
||||
const brokerId = (createResponse.body as Response<Broker>).data
|
||||
.brokerId;
|
||||
|
||||
// 查询单个券商
|
||||
return request(app.getHttpServer())
|
||||
.get(`/api/broker/${brokerId}`)
|
||||
.expect(200)
|
||||
.expect((res) => {
|
||||
expect(res.body.code).toBe(0);
|
||||
expect(res.body.data.brokerId).toBe(brokerId);
|
||||
expect(res.body.data.brokerCode).toBe('GET_ONE_TEST');
|
||||
});
|
||||
});
|
||||
|
||||
it('应该返回 404 当券商不存在时', () => {
|
||||
return request(app.getHttpServer())
|
||||
.get('/api/broker/99999')
|
||||
.expect(404)
|
||||
.expect((res) => {
|
||||
expect(res.body.code).toBe(404);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('PATCH /api/broker/:id', () => {
|
||||
it('应该成功更新券商', async () => {
|
||||
// 先创建一个券商
|
||||
const createResponse = await request(app.getHttpServer())
|
||||
.post('/api/broker')
|
||||
.send({
|
||||
brokerCode: 'UPDATE_TEST',
|
||||
brokerName: '更新测试',
|
||||
region: 'CN',
|
||||
})
|
||||
.expect(201);
|
||||
|
||||
const brokerId = (createResponse.body as Response<Broker>).data
|
||||
.brokerId;
|
||||
|
||||
// 更新券商
|
||||
return request(app.getHttpServer())
|
||||
.patch(`/api/broker/${brokerId}`)
|
||||
.send({
|
||||
brokerName: '更新后的名称',
|
||||
})
|
||||
.expect(200)
|
||||
.expect((res) => {
|
||||
expect(res.body.code).toBe(0);
|
||||
expect(res.body.data.brokerName).toBe('更新后的名称');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('DELETE /api/broker/:id', () => {
|
||||
it('应该成功删除券商', async () => {
|
||||
// 先创建一个券商
|
||||
const createResponse = await request(app.getHttpServer())
|
||||
.post('/api/broker')
|
||||
.send({
|
||||
brokerCode: 'DELETE_TEST',
|
||||
brokerName: '删除测试',
|
||||
region: 'CN',
|
||||
})
|
||||
.expect(201);
|
||||
|
||||
const brokerId = (createResponse.body as Response<Broker>).data
|
||||
.brokerId;
|
||||
|
||||
// 删除券商
|
||||
await request(app.getHttpServer())
|
||||
.delete(`/api/broker/${brokerId}`)
|
||||
.expect(204);
|
||||
|
||||
// 验证已删除
|
||||
await request(app.getHttpServer())
|
||||
.get(`/api/broker/${brokerId}`)
|
||||
.expect(404);
|
||||
});
|
||||
});
|
||||
});
|
||||
150
apps/api/test/modules/broker/broker.service.integration.spec.ts
Normal file
150
apps/api/test/modules/broker/broker.service.integration.spec.ts
Normal file
@@ -0,0 +1,150 @@
|
||||
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 { BrokerService } from '../../../src/modules/broker/broker.service';
|
||||
import { Broker } from '../../../src/modules/broker/broker.entity';
|
||||
import { BrokerModule } from '../../../src/modules/broker/broker.module';
|
||||
import { CreateBrokerDto } from '../../../src/modules/broker/dto/create-broker.dto';
|
||||
import { BatchCreateBrokerDto } from '../../../src/modules/broker/dto/batch-create-broker.dto';
|
||||
import { getDatabaseConfig } from '../../../src/database/database.config';
|
||||
import { brokersConfig } from '../../../src/modules/broker/config/brokers.config';
|
||||
|
||||
describe('BrokerService (集成测试)', () => {
|
||||
let service: BrokerService;
|
||||
let repository: Repository<Broker>;
|
||||
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],
|
||||
}),
|
||||
BrokerModule,
|
||||
],
|
||||
}).compile();
|
||||
|
||||
service = module.get<BrokerService>(BrokerService);
|
||||
repository = module.get<Repository<Broker>>(getRepositoryToken(Broker));
|
||||
|
||||
// 清理测试数据(可选)
|
||||
await repository.clear();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
// 测试结束后清理
|
||||
// await repository.clear();
|
||||
await module.close();
|
||||
});
|
||||
|
||||
describe.skip('create - 集成测试', () => {
|
||||
it('应该成功在数据库中创建券商', async () => {
|
||||
const createBrokerDto: CreateBrokerDto = {
|
||||
brokerCode: 'HTZQ_TEST',
|
||||
brokerName: '华泰证券测试',
|
||||
region: 'CN',
|
||||
sortOrder: 1,
|
||||
isActive: true,
|
||||
};
|
||||
|
||||
const result = await service.create(createBrokerDto);
|
||||
console.log(result);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result.brokerId).toBeDefined();
|
||||
expect(result.brokerCode).toBe(createBrokerDto.brokerCode);
|
||||
expect(result.brokerName).toBe(createBrokerDto.brokerName);
|
||||
|
||||
// 验证数据确实保存到数据库
|
||||
const savedBroker = await repository.findOne({
|
||||
where: { brokerId: result.brokerId },
|
||||
});
|
||||
expect(savedBroker).toBeDefined();
|
||||
expect(savedBroker?.brokerCode).toBe(createBrokerDto.brokerCode);
|
||||
|
||||
// 清理
|
||||
// await repository.remove(result);
|
||||
});
|
||||
|
||||
it('应该使用数据库默认值', async () => {
|
||||
const createBrokerDto: CreateBrokerDto = {
|
||||
brokerCode: 'ZSZQ_TEST',
|
||||
brokerName: '招商证券测试',
|
||||
region: 'CN',
|
||||
// 不提供 sortOrder 和 isActive
|
||||
};
|
||||
|
||||
const result = await service.create(createBrokerDto);
|
||||
|
||||
expect(result.sortOrder).toBe(0); // 数据库默认值
|
||||
expect(result.isActive).toBe(true); // 数据库默认值
|
||||
|
||||
// 清理
|
||||
// await repository.remove(result);
|
||||
});
|
||||
});
|
||||
|
||||
describe.only('batchCreate - 集成测试', () => {
|
||||
it('应该成功从配置文件批量创建券商', async () => {
|
||||
// 从配置文件读取券商数据
|
||||
const batchCreateDto: BatchCreateBrokerDto = {
|
||||
brokers: brokersConfig,
|
||||
};
|
||||
|
||||
const result = await service.batchCreate(batchCreateDto);
|
||||
|
||||
// 验证创建成功
|
||||
expect(result).toBeDefined();
|
||||
expect(Array.isArray(result)).toBe(true);
|
||||
expect(result.length).toBeGreaterThan(0);
|
||||
|
||||
// 验证数据确实保存到数据库
|
||||
const savedBrokers = await repository.find({
|
||||
where: brokersConfig.map((broker) => ({
|
||||
brokerCode: broker.brokerCode,
|
||||
region: broker.region,
|
||||
})),
|
||||
});
|
||||
|
||||
expect(savedBrokers.length).toBe(brokersConfig.length);
|
||||
|
||||
// 验证部分数据
|
||||
const cnBrokers = savedBrokers.filter((b) => b.region === 'CN');
|
||||
const hkBrokers = savedBrokers.filter((b) => b.region === 'HK');
|
||||
const usBrokers = savedBrokers.filter((b) => b.region === 'US');
|
||||
|
||||
expect(cnBrokers.length).toBeGreaterThan(0);
|
||||
expect(hkBrokers.length).toBeGreaterThan(0);
|
||||
expect(usBrokers.length).toBeGreaterThan(0);
|
||||
|
||||
// 验证 brokerImage 为 null 或 undefined
|
||||
savedBrokers.forEach((broker) => {
|
||||
expect(broker.brokerImage).toBeFalsy(); // null 或 undefined 都通过
|
||||
});
|
||||
|
||||
// 注意:不删除数据,保留在数据库中
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user