coverlet无法检测模块(ArgumentException):部分项目覆盖率为0求助
Coverlet 3.2.0无法检测部分.NET Core 3.1项目,覆盖率为0(GuidHeap数组越界错误)
问题概述
解决方案中部分项目的单元测试可正常执行,但覆盖率始终为0;其余项目配置一致却能正常生成覆盖率数据。
环境配置
- coverlet: 3.2.0
- xUnit: 2.4.2
- MSFT.Net.Test.SDK: 16.6.1
- .NET Core 3.1
测试执行命令
dotnet.exe test c:\TestProject.csproj --collect "XPlat Code Coverage" --results-directory C:\CodeCoverage --configuration Release
诊断日志中的错误信息
启用--diag后,日志输出以下关键错误:
[coverlet]Unable to instrument module: C:\Development\EBH\RefreshAPI\src\EBillingHub.InvoiceExtraction.Business.Logic.Tests.Unit\bin\Release\netcoreapp3.1\EBillingHub.InvoiceExtraction.Business.Logic.dll System.ArgumentException: Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection. at System.Buffer.BlockCopy(Array src, Int32 srcOffset, Array dst, Int32 dstOffset, Int32 count) at Mono.Cecil.Metadata.GuidHeap.Read(UInt32 index) at Mono.Cecil.MetadataReader.InitializeCustomDebugInformations() at Mono.Cecil.MetadataReader.GetCustomDebugInformation(ICustomDebugInformationProvider provider) at Mono.Cecil.Cil.PortablePdbReader.ReadModule() at Mono.Cecil.Cil.PortablePdbReader.ProcessDebugHeader(ImageDebugHeader header) at Mono.Cecil.ModuleDefinition.ReadSymbols(ISymbolReader reader, Boolean throwIfSymbolsAreNotMaching) at Mono.Cecil.ModuleReader.ReadSymbols(ModuleDefinition module, ReaderParameters parameters) at Mono.Cecil.ModuleReader.CreateModule(Image image, ReaderParameters parameters) at Mono.Cecil.ModuleDefinition.ReadModule(Disposable1 stream, String fileName, ReaderParameters parameters) at Mono.Cecil.ModuleDefinition.ReadModule(Stream stream, ReaderParameters parameters) at Coverlet.Core.Instrumentation.Instrumenter.CreateReachabilityHelper() in //src/coverlet.core/Instrumentation/Instrumenter.cs:line 203 at Coverlet.Core.Instrumentation.Instrumenter.InstrumentModule() in //src/coverlet.core/Instrumentation/Instrumenter.cs:line 209 at Coverlet.Core.Instrumentation.Instrumenter.Instrument() in //src/coverlet.core/Instrumentation/Instrumenter.cs:line 153 at Coverlet.Core.Coverage.PrepareModules() in //src/coverlet.core/Coverage.cs:line 135 TpTrace Warning: 0 : 22036, 1, 2023/03/16, 17:52:05.273, 364420612049, datacollector.dll, [coverlet]Unable to instrument module: C:\Development\EBH\RefreshAPI\src\EBillingHub.InvoiceExtraction.Business.Logic.Tests.Unit\bin\Release\netcoreapp3.1\EBillingHub.InvoiceExtraction.BusinessLogic.dll System.ArgumentException: Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection. at System.Buffer.BlockCopy(Array src, Int32 srcOffset, Array dst, Int32 dstOffset, Int32 count) at Mono.Cecil.Metadata.GuidHeap.Read(UInt32 index) at Mono.Cecil.MetadataReader.InitializeCustomDebugInformations() at Mono.Cecil.MetadataReader.GetCustomDebugInformation(ICustomDebugInformationProvider provider) at Mono.Cecil.Cil.PortablePdbReader.ReadModule() at Mono.Cecil.Cil.PortablePdbReader.ProcessDebugHeader(ImageDebugHeader header) at Mono.Cecil.ModuleDefinition.ReadSymbols(ISymbolReader reader, Boolean throwIfSymbolsAreNotMaching) at Mono.Cecil.ModuleReader.ReadSymbols(ModuleDefinition module, ReaderParameters parameters) at Mono.Cecil.ModuleReader.CreateModule(Image image, ReaderParameters parameters) at Mono.Cecil.ModuleDefinition.ReadModule(Disposable1 stream, String fileName, ReaderParameters parameters) at Mono.Cecil.ModuleDefinition.ReadModule(Stream stream, ReaderParameters parameters) at Coverlet.Core.Instrumentation.Instrumenter.CreateReachabilityHelper() in //src/coverlet.core/Instrumentation/Instrumenter.cs:line 203 at Coverlet.Core.Instrumentation.Instrumenter.InstrumentModule() in //src/coverlet.core/Instrumentation/Instrumenter.cs:line 209 at Coverlet.Core.Instrumentation.Instrumenter.Instrument() in //src/coverlet.core/Instrumentation/Instrumenter.cs:line 153 at Coverlet.Core.Coverage.PrepareModules() in //src/coverlet.core/Coverage.cs:line 135
关联Cecil代码分析
查看Mono.Cecil的GuidHeap实现,错误触发于Read方法的数组拷贝逻辑:
sealed class GuidHeap : Heap { public GuidHeap (byte [] data) : base (data) { } public Guid Read (uint index) { const int guid_size = 16; if (index == 0 || ((index - 1) + guid_size) > data.Length) return new Guid (); var buffer = new byte [guid_size]; Buffer.BlockCopy (this.data, (int) ((index - 1) * guid_size), buffer, 0, guid_size); return new Guid (buffer); } }
判断逻辑虽做了边界检查,但实际执行时仍出现数组越界,推测是调试符号文件(pdb)中的GUID堆数据损坏或索引异常。
临时现象
修改项目名称并构建,再改回原名(不清理输出目录,保留两个不同名称的DLL),此时被重命名过的DLL可被正常检测并生成覆盖率数据。
可行解决办法
清理缓存后重新构建
完全删除项目的bin和obj目录,重新执行构建和测试命令,解决旧缓存导致的pdb/DLL损坏问题。升级coverlet版本
coverlet 3.2.0存在与Mono.Cecil的兼容性问题,升级至3.2.x补丁版或更高稳定版本可修复该数组越界错误。禁用Reachability分析
创建coverlet.runsettings配置文件,禁用触发错误的Reachability分析功能:<RunSettings> <DataCollectionRunSettings> <DataCollectors> <DataCollector friendlyName="XPlat Code Coverage"> <Configuration> <EnableReachabilityAnalysis>false</EnableReachabilityAnalysis> </Configuration> </DataCollector> </DataCollectors> </DataCollectionRunSettings> </RunSettings>执行测试时添加
--settings coverlet.runsettings参数。检查调试符号配置
确保Release模式下项目生成完整的可移植调试符号,在项目文件中显式配置:<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> <DebugType>portable</DebugType> <DebugSymbols>true</DebugSymbols> </PropertyGroup>
内容的提问来源于stack exchange,提问作者Siarhei Machel
相关产品推荐
相关产品推荐

