From f63714f1e12a0cbb0de7aed281e36ea2d6a01788 Mon Sep 17 00:00:00 2001 From: GeWuYou <95328647+GeWuYou@users.noreply.github.com> Date: Fri, 3 Apr 2026 15:50:45 +0800 Subject: [PATCH] =?UTF-8?q?test(game):=20=E6=B7=BB=E5=8A=A0=E6=B8=B8?= =?UTF-8?q?=E6=88=8F=E6=A8=A1=E5=9D=97=E9=9B=86=E6=88=90=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 创建了 GFramework.Game.Tests 测试项目配置文件 - 添加了 Microsoft.NET.Test.Sdk、Moq、NUnit 等测试依赖包 - 配置了项目引用包括 GFramework.Game、GFramework.Core 和源代码生成器 - 实现了自动生成配置消费者集成测试验证功能 - 添加了怪物配置模式定义用于端到端测试验证 - 创建了源代码生成器目标文件实现自动化配置收集 - 验证了消费者项目自动拾取 schema 并生成绑定的功能 --- ...GeneratedConfigConsumerIntegrationTests.cs | 125 ++++++++++++++++++ .../GFramework.Game.Tests.csproj | 15 +++ .../schemas/monster.schema.json | 24 ++++ ...eWuYou.GFramework.SourceGenerators.targets | 14 +- 4 files changed, 175 insertions(+), 3 deletions(-) create mode 100644 GFramework.Game.Tests/Config/GeneratedConfigConsumerIntegrationTests.cs create mode 100644 GFramework.Game.Tests/schemas/monster.schema.json diff --git a/GFramework.Game.Tests/Config/GeneratedConfigConsumerIntegrationTests.cs b/GFramework.Game.Tests/Config/GeneratedConfigConsumerIntegrationTests.cs new file mode 100644 index 00000000..a419c260 --- /dev/null +++ b/GFramework.Game.Tests/Config/GeneratedConfigConsumerIntegrationTests.cs @@ -0,0 +1,125 @@ +using System.IO; +using GFramework.Game.Config; +using GFramework.Game.Config.Generated; + +namespace GFramework.Game.Tests.Config; + +/// +/// 验证消费者项目通过 `schemas/**/*.schema.json` 自动拾取 schema 后, +/// 可以直接编译并使用生成的注册辅助、强类型访问入口与运行时加载链路。 +/// +[TestFixture] +public class GeneratedConfigConsumerIntegrationTests +{ + /// + /// 为每个端到端测试准备独立的配置根目录,避免编译期 schema 资产与运行时写入互相污染。 + /// + [SetUp] + public void SetUp() + { + _rootPath = Path.Combine(Path.GetTempPath(), "GFramework.GeneratedConfigTests", Guid.NewGuid().ToString("N")); + Directory.CreateDirectory(_rootPath); + } + + /// + /// 清理测试过程中创建的临时消费者目录。 + /// + [TearDown] + public void TearDown() + { + if (Directory.Exists(_rootPath)) + { + Directory.Delete(_rootPath, true); + } + } + + private string _rootPath = null!; + + /// + /// 验证生成器自动拾取消费者项目的 schema 后, + /// 可以用生成的注册辅助完成加载,并通过强类型表包装访问运行时数据。 + /// + [Test] + public async Task LoadAsync_Should_Support_Generated_Bindings_In_Consumer_Project() + { + CreateFile( + "schemas/monster.schema.json", + """ + { + "title": "Monster Config", + "description": "Defines one monster entry for the end-to-end consumer integration test.", + "type": "object", + "required": ["id", "name", "hp"], + "properties": { + "id": { + "type": "integer", + "description": "Monster identifier." + }, + "name": { + "type": "string", + "description": "Monster display name." + }, + "hp": { + "type": "integer", + "description": "Monster base health." + } + } + } + """); + CreateFile( + "monster/slime.yaml", + """ + id: 1 + name: Slime + hp: 10 + """); + CreateFile( + "monster/goblin.yaml", + """ + id: 2 + name: Goblin + hp: 30 + """); + + var registry = new ConfigRegistry(); + var loader = new YamlConfigLoader(_rootPath) + .RegisterMonsterTable(); + + await loader.LoadAsync(registry); + + var table = registry.GetMonsterTable(); + + Assert.Multiple(() => + { + Assert.That(MonsterConfigBindings.TableName, Is.EqualTo("monster")); + Assert.That(MonsterConfigBindings.ConfigRelativePath, Is.EqualTo("monster")); + Assert.That(MonsterConfigBindings.SchemaRelativePath, Is.EqualTo("schemas/monster.schema.json")); + Assert.That(table.Count, Is.EqualTo(2)); + Assert.That(table.Get(1).Name, Is.EqualTo("Slime")); + Assert.That(table.Get(2).Hp, Is.EqualTo(30)); + Assert.That(registry.TryGetMonsterTable(out var generatedTable), Is.True); + Assert.That(generatedTable, Is.Not.Null); + Assert.That(generatedTable!.All().Select(static config => config.Name), + Is.EquivalentTo(new[] { "Slime", "Goblin" })); + }); + } + + /// + /// 在临时消费者根目录中创建测试文件。 + /// + /// 相对根目录的文件路径。 + /// 要写入的文件内容。 + private void CreateFile( + string relativePath, + string content) + { + var path = Path.Combine(_rootPath, relativePath.Replace('/', Path.DirectorySeparatorChar)); + var directoryPath = Path.GetDirectoryName(path); + if (!string.IsNullOrEmpty(directoryPath)) + { + Directory.CreateDirectory(directoryPath); + } + + File.WriteAllText(path, content.Replace("\n", Environment.NewLine, StringComparison.Ordinal)); + } +} \ No newline at end of file diff --git a/GFramework.Game.Tests/GFramework.Game.Tests.csproj b/GFramework.Game.Tests/GFramework.Game.Tests.csproj index 7df909e8..6ad45dbe 100644 --- a/GFramework.Game.Tests/GFramework.Game.Tests.csproj +++ b/GFramework.Game.Tests/GFramework.Game.Tests.csproj @@ -19,6 +19,21 @@ + + + + + + diff --git a/GFramework.Game.Tests/schemas/monster.schema.json b/GFramework.Game.Tests/schemas/monster.schema.json new file mode 100644 index 00000000..4b16aa59 --- /dev/null +++ b/GFramework.Game.Tests/schemas/monster.schema.json @@ -0,0 +1,24 @@ +{ + "title": "Monster Config", + "description": "Defines one monster entry for the generated consumer integration test.", + "type": "object", + "required": [ + "id", + "name", + "hp" + ], + "properties": { + "id": { + "type": "integer", + "description": "Monster identifier." + }, + "name": { + "type": "string", + "description": "Monster display name." + }, + "hp": { + "type": "integer", + "description": "Monster base health." + } + } +} diff --git a/GFramework.SourceGenerators/GeWuYou.GFramework.SourceGenerators.targets b/GFramework.SourceGenerators/GeWuYou.GFramework.SourceGenerators.targets index b66b376d..c2c3af2d 100644 --- a/GFramework.SourceGenerators/GeWuYou.GFramework.SourceGenerators.targets +++ b/GFramework.SourceGenerators/GeWuYou.GFramework.SourceGenerators.targets @@ -12,9 +12,17 @@ - - - + + + +