资讯动态

CoreCLR 测试配置:从 Kind 推断到脚本生成

发布时间:2026/10/16 1:38:17 来源:尧图企业网站定制
CoreCLR 测试配置从 Kind 推断到脚本生成【免费下载链接】runtime.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.项目地址: https://gitcode.com/GitHub_Trending/runtime6/runtime在 .NET runtime 仓库的src/tests/下每个测试工程从被 MSBuild 打开的那一刻起就要依次回答四个问题它属于哪种种类、在当前目标平台上要不要构建、要不要生成执行脚本、在哪些压力模式下必须被排除。这条判定链由十几个 MSBuild 属性驱动集中在 src/tests/Directory.Build.targets 与src/tests/Common/下的若干 targets 中。下文按 MSBuild 的执行顺序梳理这条链路随后覆盖三个日常操作加回归测试、建 C# 测试工程、拆分合并运行器。测试工程如何分类CLRTestKind 的默认推断与行为开关工程不写CLRTestKind时推断规则就两行CLRTestKind Condition$(CLRTestKind) and $(OutputType) ExeBuildAndRun/CLRTestKind CLRTestKind Condition$(CLRTestKind) SharedLibrary/CLRTestKind即输出为Exe的工程默认BuildAndRun其余典型如类库落到SharedLibrary。注意一个前置细节RequiresProcessIsolationtrue的工程会被先强制推断出OutputTypeExe第 17 行所以需要进程隔离与可运行是绑定的。种类确定后紧随其后的Choose块第 30-64 行展开出一组内部开关CLRTestKind是否编译源码是否产出可执行文件是否生成运行脚本是否需要运行典型场景BuildAndRunExe 默认是是是是绝大多数回归测试BuildOnly是是否否编译期校验、被复用的依赖库RunOnly否否是是同一可执行文件换参数再跑一遍SharedLibrary非 Exe 默认是否否否多测试共用的托管库RunOnly的依赖声明值得单独说明它不产出任何可执行文件却需要有个东西可跑于是工程里给出CLRTestProjectToRun指向真正的目标工程基础设施在第 84-88 行把它转成ProjectReference先行构建ItemGroup Condition $(_CLRTestNeedsProjectToRun) ProjectReference Include$(CLRTestProjectToRun) Privatefalse/Private /ProjectReference /ItemGroup执行脚本生成阶段src/tests/Common/CLRTest.Execute.targets 的FetchExternalProperties目标据此区分两种取法RunOnly时用[MSBuild]::MakeRelative算出被引用工程的输出路径作为InputAssemblyNameBuildAndRun则直接用$(AssemblyName).dll。最后由GenerateExecutionScriptsInternal统一产出 BatchWindows或 BashUnix脚本。优先级分层低优先级测试如何随高优先级一起运行CLRTestPriority缺省为 0第 21 行语义是越重要越小——priority 0 应该是全仓库中体积最小、最核心的子集。新测试若要降低优先级必须在工程里显式写CLRTestPriority2/CLRTestPriority这样的降级声明不存在升优先级的概念。包含关系体现在批量构建阈值上BuildAllProjectstrue时只有CLRTestPriority CLRTestPriorityToBuild的工程才会被置_WillCLRTestProjectBuildtrue第 99 行。换言之开发者选跑 priority 2 的批次0、1、2 三档全部会执行阈值只向下截断不会向上放大。仓库里的现成对照src/tests/GC/API/GC/Collect.csproj 声明CLRTestPriority1/CLRTestPriority原因是该用例依赖互不干扰的进程级 GC 状态同目录的 src/tests/GC/API/GC/Collect_Aggressive.csproj 则显式留在 priority 0并附带CLRTestTargetUnsupported Condition$(RuntimeFlavor) ! coreclrtrue/CLRTestTargetUnsupported把非 CoreCLR 变体挡在构建之外。CI 侧对这类分层的消费形态大致如下跨平台编译三禁令托管部分为什么统一在 OSX 上构建CI 的做法是所有测试的托管部分先在 OSX 上完成构建各目标平台只负责跑其中的子集。由此推出三条硬约束任何测试的托管代码都不得出现依赖目标平台的条件编译指令依赖目标平台的条件 include 文件依赖目标平台的DefineConstants/条件定义。配套原则是测试引用的任何System.Private.CoreLib类型与方法必须在所有平台都能通过编译也就是说要有足够多的实现让 C# 编译器找得到符号在并不真正实现的平台桩方法直接throw new PlatformNotSupportedException()即可。若某个用例因已知缺陷失败挂上[ActiveIssue]特性而不是让它红着。平台可用性在构建判定层由两个属性表达二者都汇入_WillCLRTestProjectBuild第 94-107 行CLRTestTargetUnsupported按条件排除特定目标例如CLRTestTargetUnsupported Condition$(TargetArchitecture) arm64true/CLRTestTargetUnsupported对应第 100 行分支DisableProjectBuild无条件取消构建第 101 行分支。还有一批衍生场景由同一机制承接例如MonoAotIncompatibletrue且运行于 mono 的minifullaot/llvmfullaot变体时第 15 行会先把DisableProjectBuild置 trueNativeAotIncompatibletrue且TestBuildModenativeaot时走第 102 行分支。判定结果为不构建时第 561 行导入Common/nobuild.targets让后续构建目标整体空转。与某种压力模式不兼容六个开关各在哪个环节生效所有排除某运行模式的声明都写在测试工程 csproj 里全集如下属性排除的运行模式附加行为GCStressIncompatibleGCStress 注入HasDisasmChecktrue时由 CLRTest.Jit.targets 第 116 行自动置 trueJitOptimizationSensitiveJIT 压力stress编译对优化产物代码形态敏感的测试使用NativeAotIncompatibleNativeAOT 构建同时命中第 102 行构建判定分支IlasmRoundTripIncompatibleilasm 往返AlwaysUseCrossGen2true时由 CrossGen targets 第 26 行自动置 trueUnloadabilityIncompatible可回收程序集场景CLRTestIsHosted ! true的自定义宿主测试会被自动置 trueR2RIncompatibleReadyToRun 运行脚本打印 SKIPPING 提示后直接跳过GCStress 的注入路径值得看清压力批次通过 MSBuild 属性RunWithGcStress传入src/tests/Common/CLRTest.Jit.targets 末尾将其翻译成环境变量写进执行脚本CLRTestEnvironmentVariable Condition$(RunWithGcStress) ! IncludeDOTNET_GCStress Value$(RunWithGcStress) /而带反汇编检查源文件带HasDisasmCheck元数据的测试会在第 116 行被自动标记GCStressIncompatible——原因是DOTNET_GCStress会改变方法体的实际形态反汇编比对结果随之失效两者天然互斥。R2R 测试被跳过时R2RIncompatible、AlwaysUseCrossGen2 与 composite 编译ReadyToRun 相关的特殊行为全部落在 src/tests/Common/CLRTest.CrossGen.targetsR2RIncompatibletrue且当前批次要求 R2R 时Bash 脚本第 53 行与 Batch 脚本第 287 行都会先打印SKIPPING EXECUTION BECAUSE the test is incompatible with ReadyToRun然后退出。本地看到R2R 测试没跑先确认这是预期跳过还是配置遗漏。AlwaysUseCrossGen2true表示该测试专门验证 crossgen2在任何测试模式下都以 crossgen2 方式编译脚本置RunCrossGen21与CompositeBuildMode1进入 composite 流程——生成响应文件、调用$CORE_ROOT/crossgen2/crossgen2再用R2RDump对产物做--header --sc --val校验脚本同时支持--composite、--targetarch、--targetos、--method-layout:random、--hot-cold-splitting、--synthesize-random-mibc合成 PGO 数据等参数。矛盾配置会直接报错CrossGenTestfalse与AlwaysUseCrossGen2true同时出现时第 47 行抛出Setting both AlwaysUseCrossGen2 to true and CrossGenTest to false is non-sensical。构建层面同样有联动mono 风味第 104 行、开启原生 sanitizer第 105 行、nativeaot 模式第 106 行下AlwaysUseCrossGen2true的工程一律不构建且该属性会自动派生出IlasmRoundTripIncompatibletrue第 26 行。新建 C# 测试工程的完整流程模板、Fact 源生成器与退出码 100复制现有测试如src/tests/Exceptions/Finalization/Finalizer.csproj到src/tests下的新目录删除模板里的AssemblyName属性——保留它会让构建系统按错误的方式解析测试输出设置CLRTestKind与CLRTestPriority添加源文件用 XUnit 的Fact特性标记测试方法其余按需在工程内补充依赖。第 4 步背后的机制基础设施的源生成器src/tests/Common/XUnitWrapperGenerator会扫出全部Fact方法并生成Main入口由 Directory.Build.targets 第 537-543 行以OutputItemTypeAnalyzer的形式注入到需要运行的 C# 工程BuildAsStandalone、RequiresProcessIsolation、合并目录或合并运行器场景。也可以自定义Main此时遵守退出码约定成功返回100失败返回任意非 100 值——执行脚本侧的默认成功码正是CLRTestExitCode100/CLRTestExitCodeCLRTest.Execute.targets 第 37 行static public int Main(string[] notUsed) { try { // 测试场景 } catch (Exception e) { Console.WriteLine($Test Failure: {e}); return 101; } return 100; }依赖引用分两种托管库写ProjectReference Include../ManagedDll.csproj /原生依赖写CMakeProjectReference Include../NativeDll/CMakeLists.txt /后者由 Directory.Build.targets 的ResolveCMakeNativeProjectReference目标识别为NativeProjectReference构建完成后经CopyNativeProjectBinaries复制到测试输出目录。需要新增 NuGet 包时不要写进单个测试工程而是更新 src/tests/Common/test_dependencies/test_dependencies.csproj——该工程自身是BuildOnly种类集中承载Microsoft.Diagnostics.Tools.RuntimeClient、xunit.analyzers等测试依赖并负责把库的运行时文件汇集进 Core_Root。构建完成后按 CI 的重跑失败测试流程本地验证一遍确认脚本与退出码均符合预期。添加 JIT 回归测试源文件通配运行器与独立工程的分界两条路线的取舍标准只有一条是否需要与既有运行器不同的编译设置、独立程序集、原生依赖或进程隔离。不需要的话直接把Runtime_issue_number.cs放进src/tests/JIT/Regression_ro_2/或其子目录即可。该运行器的工程里只有一句通配Compile Include**\*.cs /递归纳入目录下全部源文件因此新增测试既不用改工程文件也不用单独建目录被多个运行器共享的源码放在某个运行器目录中由其余运行器显式 include。需要独立工程时放到src/tests/JIT/Regression_2/Runtime_issue_number/下Regression_2.csproj以递归发现工程而非直接编译源码的方式组织这些子工程Regression_3.csproj同理管理src/tests/JIT/Regression_3/下既有的GitHub_*、DevDiv_*等工程化测试。源码与配套文件务必与工程放在一起——放进源文件通配运行器的目录会被误编译进别的程序集。拆分巨型合并运行器MergedWrapperProjectReference 与 stress 条纹合并测试运行器以 src/tests/JIT/Methodical/Methodical_d1.csproj 为典型声明HasMergedInTeststrue/HasMergedInTests用通配批量引入子工程再显式Compile共享源文件末尾导入$(TestSourceDir)MergedTestRunner.targetsPropertyGroup HasMergedInTeststrue/HasMergedInTests /PropertyGroup ItemGroup MergedWrapperProjectReference Includea*/**/*_d.??proj / MergedWrapperProjectReference Includeb*/**/*_d.??proj / /ItemGroup当运行器体量大到 GC Stress 下耗时失控时引入条纹切分设置NumberOfStripesToUseInStress10/NumberOfStripesToUseInStress例如取 10。合并运行器缺省值为 1Directory.Build.targets 第 319-321 行该数值随后驱动GenerateMarkerFiles目标产出形如$(MSBuildProjectName).MergedTestAssembly.0.10.MergedTestAssemblyForStress的应力标记文件第 426-431 行CI 压力批次据此把测试组切条并行。超过 99 会直接报错Attempt to split into too many stripes...。执行侧合并运行器接受[testFilterString] [-stripe whichStripe totalStripes]形式的命令行参数testFilterString目前只支持完全限定名子串。条纹有等价的环境变量写法TEST_HARNESS_STRIPE_TO_EXECUTE值必须是.which.total格式whichStripe从 0 起算src/tests/Common/XUnitWrapperLibrary/TestFilter.cs 同时解析-stripe与该变量。实践提示本地想只看某一条纹的行为直接export TEST_HARNESS_STRIPE_TO_EXECUTE.2.4再跑运行器即可复现第 3 条共 4 条的执行切片无需改动任何 CI 配置。速查与排错属性全集和两条排查路径属性默认值何时设置生效环节CLRTestKindExe 工程BuildAndRun否则SharedLibrary需要覆盖推断结果时种类推断与行为开关第 19-20、30-64 行CLRTestPriority0降级时批量构建阈值第 99 行CLRTestTargetUnsupported空按平台排除构建判定第 100 行DisableProjectBuild空无条件排除构建判定第 101 行GCStressIncompatible空用例对 GC 压力敏感执行脚本JitOptimizationSensitive空用例对优化形态敏感执行脚本NativeAotIncompatible空AOT 路径无对应实现构建判定第 102 行 脚本IlasmRoundTripIncompatible空依赖托管源码语义脚本 标记文件UnloadabilityIncompatible空依赖进程生命周期假设脚本 标记文件R2RIncompatible空依赖 JIT 编译路径执行脚本SKIPPING 跳过AlwaysUseCrossGen2空专门验证 crossgen2构建判定第 104-106 行 脚本CrossGenTesttrueR2R 通过中不做标准 R2R 编译脚本与AlwaysUseCrossGen2true矛盾时第 47 行报错NumberOfStripesToUseInStress1合并运行器stress 耗时过长应力标记文件第 426-431 行上限 99CLRTestExitCode100自定义成功码执行脚本 两条高频排查路径测试没被构建从_WillCLRTestProjectBuild的第 94-107 行逐条核对哪个分支把它置 false——CLRTestTargetUnsupported、DisableProjectBuild、NativeAotIncompatible、AlwaysUseCrossGen2的风味冲突都在其中命中后构建会转入nobuild.targets第 561 行空转。运行脚本没生成GenerateRunScript只对BuildAndRun与RunOnly为 trueRunOnly还需CLRTestProjectToRun指向真实存在的可构建工程否则FetchExternalProperties拿不到InputAssemblyName。源码阅读路径建议src/tests/Directory.Build.targets→src/tests/Common/CLRTest.Execute.targets→src/tests/Common/CLRTest.CrossGen.targets→src/tests/Common/CLRTest.Jit.targets→src/tests/Common/test_dependencies/test_dependencies.csproj→src/tests/JIT/Methodical/Methodical_d1.csproj。动手前建议先打开一个你即将参照的现有工程 csproj对照速查表逐项核对其属性取值再决定自己的工程需要声明哪几项——这比从零配置更不容易漏掉隐含的风味冲突。【免费下载链接】runtime.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.项目地址: https://gitcode.com/GitHub_Trending/runtime6/runtime创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑