* feat(core): 启用 TypeScript 最严格的类型检查 * ci: 配置 Codecov 以适应类型安全改进 * fix(core): 修复 CodeQL 安全警告 * fix(core): eslint.config.mjs
207 lines
7.4 KiB
TypeScript
207 lines
7.4 KiB
TypeScript
import { Injectable, Inject, isInjectable, getInjectMetadata, createInstance, registerInjectable } from '../../src/Core/DI';
|
||
import { ServiceContainer } from '../../src/Core/ServiceContainer';
|
||
import type { IService } from '../../src/Core/ServiceContainer';
|
||
|
||
// 测试服务类
|
||
@Injectable()
|
||
class SimpleService implements IService {
|
||
public value: string = 'simple';
|
||
|
||
dispose() {
|
||
// 清理资源
|
||
}
|
||
}
|
||
|
||
@Injectable()
|
||
class DependentService implements IService {
|
||
constructor(
|
||
@Inject(SimpleService) public simpleService: SimpleService
|
||
) {}
|
||
|
||
dispose() {
|
||
// 清理资源
|
||
}
|
||
}
|
||
|
||
@Injectable()
|
||
class MultiDependencyService implements IService {
|
||
constructor(
|
||
@Inject(SimpleService) public service1: SimpleService,
|
||
@Inject(DependentService) public service2: DependentService
|
||
) {}
|
||
|
||
dispose() {
|
||
// 清理资源
|
||
}
|
||
}
|
||
|
||
// 非Injectable类(用于测试错误情况)
|
||
class NonInjectableService implements IService {
|
||
dispose() {}
|
||
}
|
||
|
||
describe('DI - 依赖注入装饰器测试', () => {
|
||
let container: ServiceContainer;
|
||
|
||
beforeEach(() => {
|
||
container = new ServiceContainer();
|
||
});
|
||
|
||
describe('@Injectable 装饰器', () => {
|
||
test('应该正确标记类为可注入', () => {
|
||
expect(isInjectable(SimpleService as any)).toBe(true);
|
||
expect(isInjectable(DependentService as any)).toBe(true);
|
||
});
|
||
|
||
test('未标记的类不应该是可注入的', () => {
|
||
expect(isInjectable(NonInjectableService as any)).toBe(false);
|
||
});
|
||
});
|
||
|
||
describe('@Inject 装饰器', () => {
|
||
test('应该记录参数注入元数据', () => {
|
||
const metadata = getInjectMetadata(DependentService as any);
|
||
expect(metadata.size).toBe(1);
|
||
expect(metadata.get(0)).toBe(SimpleService);
|
||
});
|
||
|
||
test('应该记录多个参数的注入元数据', () => {
|
||
const metadata = getInjectMetadata(MultiDependencyService as any);
|
||
expect(metadata.size).toBe(2);
|
||
expect(metadata.get(0)).toBe(SimpleService);
|
||
expect(metadata.get(1)).toBe(DependentService);
|
||
});
|
||
});
|
||
|
||
describe('createInstance', () => {
|
||
test('应该创建无依赖的实例', () => {
|
||
container.registerSingleton(SimpleService);
|
||
const instance = createInstance(SimpleService, container);
|
||
|
||
expect(instance).toBeInstanceOf(SimpleService);
|
||
expect(instance.value).toBe('simple');
|
||
});
|
||
|
||
test('应该创建有依赖的实例', () => {
|
||
container.registerSingleton(SimpleService);
|
||
container.registerSingleton(DependentService, () =>
|
||
createInstance(DependentService, container)
|
||
);
|
||
|
||
const instance = createInstance(DependentService, container);
|
||
|
||
expect(instance).toBeInstanceOf(DependentService);
|
||
expect(instance.simpleService).toBeInstanceOf(SimpleService);
|
||
});
|
||
|
||
test('应该创建有多个依赖的实例', () => {
|
||
container.registerSingleton(SimpleService);
|
||
container.registerSingleton(DependentService, () =>
|
||
createInstance(DependentService, container)
|
||
);
|
||
container.registerSingleton(MultiDependencyService, () =>
|
||
createInstance(MultiDependencyService, container)
|
||
);
|
||
|
||
const instance = createInstance(MultiDependencyService, container);
|
||
|
||
expect(instance).toBeInstanceOf(MultiDependencyService);
|
||
expect(instance.service1).toBeInstanceOf(SimpleService);
|
||
expect(instance.service2).toBeInstanceOf(DependentService);
|
||
});
|
||
|
||
test('依赖应该正确解析为单例', () => {
|
||
container.registerSingleton(SimpleService);
|
||
container.registerSingleton(DependentService, () =>
|
||
createInstance(DependentService, container)
|
||
);
|
||
|
||
const simple1 = container.resolve(SimpleService);
|
||
const dependent = createInstance(DependentService, container);
|
||
|
||
expect(dependent.simpleService).toBe(simple1);
|
||
});
|
||
});
|
||
|
||
describe('registerInjectable', () => {
|
||
test('应该注册可注入的服务', () => {
|
||
registerInjectable(container, SimpleService);
|
||
|
||
expect(container.isRegistered(SimpleService)).toBe(true);
|
||
});
|
||
|
||
test('应该自动解析依赖', () => {
|
||
registerInjectable(container, SimpleService);
|
||
registerInjectable(container, DependentService);
|
||
|
||
const instance = container.resolve(DependentService);
|
||
|
||
expect(instance).toBeInstanceOf(DependentService);
|
||
expect(instance.simpleService).toBeInstanceOf(SimpleService);
|
||
});
|
||
|
||
test('应该正确处理多层依赖', () => {
|
||
registerInjectable(container, SimpleService);
|
||
registerInjectable(container, DependentService);
|
||
registerInjectable(container, MultiDependencyService);
|
||
|
||
const instance = container.resolve(MultiDependencyService);
|
||
|
||
expect(instance).toBeInstanceOf(MultiDependencyService);
|
||
expect(instance.service1).toBeInstanceOf(SimpleService);
|
||
expect(instance.service2).toBeInstanceOf(DependentService);
|
||
expect(instance.service2.simpleService).toBeInstanceOf(SimpleService);
|
||
});
|
||
|
||
test('依赖应该是单例的', () => {
|
||
registerInjectable(container, SimpleService);
|
||
registerInjectable(container, DependentService);
|
||
|
||
const instance1 = container.resolve(DependentService);
|
||
const instance2 = container.resolve(DependentService);
|
||
const simple = container.resolve(SimpleService);
|
||
|
||
expect(instance1).toBe(instance2);
|
||
expect(instance1.simpleService).toBe(simple);
|
||
});
|
||
|
||
test('注册瞬时服务应该每次创建新实例', () => {
|
||
registerInjectable(container, SimpleService);
|
||
registerInjectable(container, DependentService, false); // 瞬时
|
||
|
||
const instance1 = container.resolve(DependentService);
|
||
const instance2 = container.resolve(DependentService);
|
||
|
||
expect(instance1).not.toBe(instance2);
|
||
expect(instance1.simpleService).toBe(instance2.simpleService); // 依赖仍然是单例
|
||
});
|
||
|
||
test('注册非Injectable类应该抛出错误', () => {
|
||
expect(() => {
|
||
registerInjectable(container, NonInjectableService as any);
|
||
}).toThrow(/not marked as @Injectable/);
|
||
});
|
||
});
|
||
|
||
describe('集成测试', () => {
|
||
test('完整的DI流程应该正常工作', () => {
|
||
// 1. 注册所有服务
|
||
registerInjectable(container, SimpleService);
|
||
registerInjectable(container, DependentService);
|
||
registerInjectable(container, MultiDependencyService);
|
||
|
||
// 2. 解析服务
|
||
const multi = container.resolve(MultiDependencyService);
|
||
|
||
// 3. 验证依赖树
|
||
expect(multi).toBeInstanceOf(MultiDependencyService);
|
||
expect(multi.service1).toBeInstanceOf(SimpleService);
|
||
expect(multi.service2).toBeInstanceOf(DependentService);
|
||
expect(multi.service2.simpleService).toBe(multi.service1); // 同一个实例
|
||
|
||
// 4. 验证服务功能
|
||
expect(multi.service1.value).toBe('simple');
|
||
});
|
||
});
|
||
});
|