refactor(tests): 优化全局引用测试的命名空间发现机制

- 添加基于真实类型的命名空间常量定义,避免硬编码字符串
- 引入 Architecture、Extensions 和 CoroutineExtensions 命名空间自动发现
- 将 FindRepositoryRoot 方法重构为 ResolveRepositoryRoot 并使用 CallerFilePath
- 更新断言逻辑以使用动态命名空间变量而非字面量字符串
- 移除对解决方案文件扫描的依赖,改用相对路径计算仓库根目录
- 添加方法参数验证和异常处理增强代码健壮性
This commit is contained in:
GeWuYou 2026-03-24 22:29:45 +08:00
parent 2d1d1a43b6
commit 20f1c987eb

View File

@ -1,4 +1,7 @@
using System.IO;
using System.Runtime.CompilerServices;
using GFramework.Core.Architectures;
using GFramework.Core.Coroutine.Extensions;
namespace GFramework.Core.Tests.Packaging;
@ -9,6 +12,27 @@ namespace GFramework.Core.Tests.Packaging;
[TestFixture]
public class TransitiveGlobalUsingsPackagingTests
{
/// <summary>
/// 使用真实类型派生架构命名空间,避免测试断言和命名空间重构脱节。
/// </summary>
private static readonly string ArchitectureNamespace = typeof(Architecture).Namespace
?? throw new InvalidOperationException(
"Architecture namespace should not be null.");
/// <summary>
/// 使用真实类型派生扩展命名空间,避免对字面量命名空间字符串的重复维护。
/// </summary>
private static readonly string ExtensionsNamespace = typeof(ContextAwareEnvironmentExtensions).Namespace
?? throw new InvalidOperationException(
"Extensions namespace should not be null.");
/// <summary>
/// 使用真实类型派生协程扩展命名空间,确保断言和源码自动发现保持一致。
/// </summary>
private static readonly string CoroutineExtensionsNamespace = typeof(CoroutineExtensions).Namespace
?? throw new InvalidOperationException(
"Coroutine extensions namespace should not be null.");
/// <summary>
/// 验证 GFramework.Core 在构建后会生成 transitive global usings props
/// 且 props 内容来自源码自动发现,并保留消费者侧排除机制。
@ -16,7 +40,7 @@ public class TransitiveGlobalUsingsPackagingTests
[Test]
public void CoreBuild_Should_Generate_AutoDiscovered_TransitiveGlobalUsingsProps()
{
var repositoryRoot = FindRepositoryRoot();
var repositoryRoot = ResolveRepositoryRoot();
var propsPath = Path.Combine(
repositoryRoot,
"GFramework.Core",
@ -27,30 +51,30 @@ public class TransitiveGlobalUsingsPackagingTests
Assert.That(File.Exists(propsPath), Is.True, $"Expected generated props to exist: {propsPath}");
var propsContent = File.ReadAllText(propsPath);
Assert.That(propsContent, Does.Contain("GFramework.Core.Extensions"));
Assert.That(propsContent, Does.Contain("GFramework.Core.Architectures"));
Assert.That(propsContent, Does.Contain("GFramework.Core.Coroutine.Extensions"));
Assert.That(propsContent, Does.Contain(ExtensionsNamespace));
Assert.That(propsContent, Does.Contain(ArchitectureNamespace));
Assert.That(propsContent, Does.Contain(CoroutineExtensionsNamespace));
Assert.That(propsContent, Does.Contain("Remove=\"@(GFrameworkExcludedUsing)\""));
Assert.That(propsContent, Does.Not.Contain("System.Runtime.CompilerServices"));
}
/// <summary>
/// 从测试输出目录向上回溯,定位包含解决方案文件的仓库根目录。
/// 基于当前测试源文件的已知位置解析仓库根目录。
/// 这里不扫描解决方案文件,避免测试对仓库布局演进产生额外脆弱性。
/// </summary>
/// <param name="sourceFilePath">由编译器注入的当前测试源文件绝对路径。</param>
/// <returns>仓库根目录绝对路径。</returns>
private static string FindRepositoryRoot()
private static string ResolveRepositoryRoot([CallerFilePath] string sourceFilePath = "")
{
var currentDirectory = new DirectoryInfo(TestContext.CurrentContext.TestDirectory);
while (currentDirectory != null)
if (string.IsNullOrWhiteSpace(sourceFilePath))
{
var solutionPath = Path.Combine(currentDirectory.FullName, "GFramework.sln");
if (File.Exists(solutionPath))
return currentDirectory.FullName;
currentDirectory = currentDirectory.Parent;
throw new InvalidOperationException("Caller file path is required to resolve the repository root.");
}
throw new DirectoryNotFoundException("Could not locate the repository root for GFramework.");
var sourceDirectory = Path.GetDirectoryName(sourceFilePath)
?? throw new DirectoryNotFoundException(
$"Could not determine the directory for source file path: {sourceFilePath}");
return Path.GetFullPath(Path.Combine(sourceDirectory, "..", ".."));
}
}