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 @@
-
-
-
+
+
+
+