You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NUnit(C#)如何在测试执行前获取测试方法内的所有代码行

实现方案

要在NUnit测试正式执行前提取测试方法内部的代码语句,可以通过NUnit自带的测试拦截能力搭配程序集符号读取实现,不需要修改测试方法本身的逻辑,具体步骤如下:

  • 依赖准备
    先在测试项目中安装Mono.Cecil、Mono.Cecil.Pdb两个NuGet包,用来读取程序集元数据、调试符号和方法体内容。
  • 自定义前置拦截特性
    NUnit提供了TestActionAttribute,重写它的BeforeTest方法即可在每个测试用例执行前注入自定义逻辑,在这个方法中可以拿到当前执行测试的方法元数据,再通过Cecil加载程序集和对应的调试符号,就能提取方法内的所有源码语句。
    完整实现代码如下:
using NUnit.Framework;
using Mono.Cecil;
using Mono.Cecil.Cil;
using System.Reflection;
using System.Linq;
using System.Collections.Generic;

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = false)]
public class CaptureTestCodeAttribute : TestActionAttribute
{
    public override void BeforeTest(TestDetails testDetails)
    {
        MethodInfo currentTestMethod = testDetails.Method;
        string assemblyPath = currentTestMethod.DeclaringType.Assembly.Location;
        
        // 读取程序集并加载调试符号
        using var module = ModuleDefinition.ReadModule(assemblyPath, new ReaderParameters
        {
            ReadSymbols = true
        });
        
        // 定位到当前执行的测试方法定义
        MethodDefinition targetMethod = module.GetTypes()
            .First(type => type.FullName == currentTestMethod.DeclaringType.FullName)
            .Methods
            .First(method => method.Name == currentTestMethod.Name 
                && method.Parameters.Count == currentTestMethod.GetParameters().Length);

        List<string> methodStatements = new List<string>();
        // 遍历方法体IL指令对应的源码序列点,提取有效代码行
        foreach (Instruction instruction in targetMethod.Body.Instructions)
        {
            SequencePoint sp = instruction.SequencePoint;
            if (sp == null) continue;
            
            string currentLine;
            // 优先从文档内存中读行,读不到就从源文件读取
            if (sp.Document.Text != null)
            {
                currentLine = sp.Document.Text.Split('\n')[sp.StartLine - 1].Trim();
            }
            else
            {
                currentLine = File.ReadLines(sp.Document.Url)
                    .Skip(sp.StartLine - 1)
                    .Take(1)
                    .First()
                    .Trim();
            }
            
            // 过滤空行、方法体大括号
            if (string.IsNullOrWhiteSpace(currentLine) || currentLine == "{" || currentLine == "}")
                continue;
            // 去重,避免同一行多个指令导致重复记录
            if (!methodStatements.Contains(currentLine))
                methodStatements.Add(currentLine);
        }
        
        // 到这一步methodStatements里就存了测试方法内的所有有效代码语句,可按需使用
        foreach (string statement in methodStatements)
        {
            TestContext.WriteLine($"捕获测试代码行:{statement}");
        }
    }

    public override ActionTargets Targets => ActionTargets.Test;
}
  • 使用方式
    直接把自定义的CaptureTestCodeAttribute标记到对应测试方法、测试类或者整个程序集上即可,对你给出的测试用例,标记后执行前就能捕获全部5条内部语句:
[Test, CaptureTestCode]
public void Test01()
{
    abc = 1;
    pqr();
    xyz();
    lmn = 9;
    zxy();
}

注意事项:要正确提取原始C#源码语句,测试项目编译时必须生成PDB调试符号,即项目生成配置中「调试信息」选项不能设为None,否则只能解析出IL指令,无法获取原始C#代码。如果只需要获取方法的IL执行逻辑,不需要PDB文件即可实现。

内容的提问来源于stack exchange,提问作者Hemant Pawar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.31 21:18:21