首页 > 基础资料 博客日记
CSharp 后端服务器如何做到:一边发请求一边看代码覆盖率
2026-06-12 13:00:03基础资料围观3次
这篇文章介绍了CSharp 后端服务器如何做到:一边发请求一边看代码覆盖率,分享给大家做个参考,收藏极客资料网收获更多编程知识
作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!
背景
最近在测试一个服务器的时候,遇到一个难题:我如何才能构造出多种请求,以便尽可能的覆盖到所有分支?
写单元测试固然是个办法,但是服务器依赖 mysql 和 redis 等组件,我需要在代码中 mock 这些依赖的组件,单元测试才能独立运行。
有没有办法做到:我发一条请求,就能立即看到代码覆盖率的变化?
下面请看我的表演——
Cooking
all-in-one 调试镜像
我首先制作了一个 DotNet 的 all-in-one 镜像: see, https://github.com/ahfuzhang/CSharpDbgContainer
镜像主要是安装了:
- DotNet SDK (10/8/6)
- dotnet tool install dotnet-coverage
- dotnet tool install dotnet-reportgenerator-globaltool
如果不想自己 build 镜像,可以使用我上传的镜像:
docker pull docker.io/ahfuzhang/csharp-dbg-all-in-one:dotnet10
see: https://hub.docker.com/repository/docker/ahfuzhang/csharp-dbg-all-in-one/general
核心代码
代码的原理很简单:
dotnet-coverage collect --session-id ${sessionID} cmd: 通过 dotnet-coverage collect 来启动程序,并且创建一个 session iddotnet-coverage snapshot --output ${coverageFile} ${sessionID}: 运行期通过 session id 采集 coverage 信息到一个文件dotnet-coverage merge {coverageFile} --output {coberturaFile} --output-format cobertura: 把 coverage 文件转换为 xml 格式reportgenerator -reports:{coberturaFile} -targetdir:{htmlDir} -reporttypes:Html: 把 xml 文件渲染为 html
public static async Task CodeCoverageCallbackAsync(HttpContext ctx)
{
var sessionId = ctx.Request.Query["session-id"].FirstOrDefault();
if (string.IsNullOrEmpty(sessionId))
{
ctx.Response.StatusCode = 400;
await ctx.Response.WriteAsync(HtmlError("Missing query parameter: session-id"));
return;
}
var uuid = Guid.NewGuid().ToString("N");
var coverageFile = $"/tmp/{uuid}.coverage";
var coberturaFile = $"/tmp/{uuid}.cobertura.xml";
var htmlDir = $"/tmp/html_{uuid}/";
// Step 1: snapshot
var (snapshotOk, snapshotErr) = await RunCommandAsync(
"dotnet-coverage",
$"snapshot --output {coverageFile} {sessionId}");
if (!snapshotOk)
{
ctx.Response.StatusCode = 500;
ctx.Response.ContentType = "text/html; charset=utf-8";
await ctx.Response.WriteAsync(HtmlError($"dotnet-coverage snapshot failed:\n{snapshotErr}"));
return;
}
// Step 2: convert to cobertura xml
var (mergeOk, mergeErr) = await RunCommandAsync(
"dotnet-coverage",
$"merge {coverageFile} --output {coberturaFile} --output-format cobertura");
if (!mergeOk)
{
ctx.Response.StatusCode = 500;
ctx.Response.ContentType = "text/html; charset=utf-8";
await ctx.Response.WriteAsync(HtmlError($"dotnet-coverage merge failed:\n{mergeErr}"));
return;
}
// Step 3: generate html report
var (reportOk, reportErr) = await RunCommandAsync(
"reportgenerator",
$"-reports:{coberturaFile} -targetdir:{htmlDir} -reporttypes:Html");
if (!reportOk)
{
ctx.Response.StatusCode = 500;
ctx.Response.ContentType = "text/html; charset=utf-8";
await ctx.Response.WriteAsync(HtmlError($"reportgenerator failed:\n{reportErr}"));
return;
}
ctx.Response.Redirect($"/code_coverage_report/{uuid}/");
}
具体代码请看:https://github.com/ahfuzhang/QiWa.DemoServer/blob/main/src/CodeCoverage/CodeCoverage.cs
编译 debug 版本的 dll
dotnet publish $(PRJ).csproj \
-r linux-x64 \
-p:DefineConstants=UNIX -p:AllowUnsafeBlocks=true \
-p:StripSymbols=false \
-p:InvariantGlobalization=true \
-p:EventSourceSupport=true \
-p:EmbedAllSources=true \
-p:DebugType=portable \
-p:DebugSymbols=true \
-p:Optimize=false \
-p:CopyOutputSymbolsToPublishDirectory=true \
-p:TieredCompilation=false \
--self-contained false \
-c Debug -o $(BUILD_DIR)
特别要注意,不要加这些选项:
- PublishAot=true : 触发 AOT 原生编译的核心标志
- StaticLinkedRuntime=true / StaticExecutable=true — 静态链接原生可执行文件
- PositionIndependentExecutable=true — 仅对原生二进制有意义
--self-contained true: 输出产物将为托管 DLL,依赖系统安装的 .NET 运行时。
为了保障工具集的版本一致性,也可以使用 docker 中的命令来编译:
docker run --rm \
-v ./:/app \
-w /app \
--user "$(id -u):$(id -g)" \
ahfuzhang/csharp-dbg-all-in-one:dotnet10 \
dotnet publish $(PRJ).csproj \
-r linux-x64 \
-p:DefineConstants=UNIX -p:AllowUnsafeBlocks=true \
-p:StripSymbols=false \
-p:InvariantGlobalization=true \
-p:EventSourceSupport=true \
-p:EmbedAllSources=true \
-p:DebugType=portable \
-p:DebugSymbols=true \
-p:Optimize=false \
-p:CopyOutputSymbolsToPublishDirectory=true \
-p:TieredCompilation=false \
--self-contained false \
-c Debug -o $(BUILD_DIR)
在 all-in-one 镜像中启动服务器
docker run --rm \
-v ./:/app \
-w /app \
--user "$(id -u):$(id -g)" \
--network host \
ahfuzhang/csharp-dbg-all-in-one:dotnet10 \
dotnet-coverage collect \
--session-id my-server-cov \
--output /tmp/demo_server.coverage \
dotnet $(BUILD_DIR)/QiWa.DemoServer.dll -- \
-log.level=debug
注意:
- 要使用
dotnet-coverage collect来启动 --session-id my-server-cov这个参数指定了 session id 的名字叫做my-server-cov,要记住这个名字dotnet xx.dll保障了程序使用 dotnet CLR 。如果静态编译的话,可能就无法采集了--这个后面是服务器的命令行参数
通过浏览器查看代码覆盖情况
打开浏览器访问:
http://127.0.0.1:8091/code_coverage?session-id=my-server-cov
- 注意:要带上
my-server-cov这个名字
会触发后端运行命令,并生成 html 报告:

每次构造请求后,我都用浏览器访问一次 /code_coverage,然后可以看见代码的覆盖率在提升。
总结
在线实时查看代码覆盖率,能够很好的解决老项目难以写可 mock 的单元测试的难题。
Have Fun. 😃
文章来源:https://www.cnblogs.com/ahfuzhang/p/20474477
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!
标签:
相关文章
最新发布
- 成为 AI 智能体工程师的 10 个步骤
- CSharp 后端服务器如何做到:一边发请求一边看代码覆盖率
- 流式输出(Streaming)原理与踩坑经验
- 凌霞 618 年中大促,全线半价,叠加满减!
- 为什么你的收藏越积越多,却越来越没用?
- 42 倍小文件性能提升、85% 吞吐增长:多云 AI 场景下的 JuiceFS 存储实践
- SkyWalking / Jaeger / ARMS 已经有了,还需要统一可观测平台吗
- How LLMs Actually Work(翻译)
- 数据库审计不是记流水账:先锁定高危动作与关键对象,再谈数据集与工具落地
- 用了 lark-cli 一个月,AI 操作飞书再也没出过岔子——说说真实体验


