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

如何编写C#单元测试确保ErrorCodeException错误码唯一

可以通过单元测试实现错误码的唯一性校验

当然可以编写单元测试来完成这个需求,而且推荐用Roslyn静态代码分析的方式来做——这种方式不需要运行业务代码,直接扫描项目里的所有C#源码,精准定位所有抛出ErrorCodeException的位置,同时校验错误码的硬编码属性和唯一性。

具体实现步骤

  1. 先在测试项目中安装Microsoft.CodeAnalysis.CSharp NuGet包,用于解析C#语法树。
  2. 编写测试代码,核心逻辑:
    • 遍历目标项目的所有.cs文件
    • 找到所有创建ErrorCodeException实例的语法节点(即throw new ErrorCodeException(xxx, "xxx")这类代码)
    • 提取第一个参数(errorCode),检查它是否是常量/字面量(确保是硬编码,而非运行时生成的值)
    • 收集所有合法错误码,检查是否存在重复

示例代码

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Xunit;
using System.IO;
using System.Collections.Generic;
using System.Linq;

public class ErrorCodeUniquenessTests
{
    [Fact]
    public void AllErrorCodeExceptionErrorCodesMustBeUniqueAndHardCoded()
    {
        // 替换为你的业务项目根目录路径
        var projectRoot = Path.Combine(Directory.GetCurrentDirectory(), "../../../YourBusinessProject");
        var csFiles = Directory.EnumerateFiles(projectRoot, "*.cs", SearchOption.AllDirectories);

        var errorCodes = new Dictionary<int, string>();

        foreach (var file in csFiles)
        {
            var code = File.ReadAllText(file);
            var syntaxTree = CSharpSyntaxTree.ParseText(code);
            var root = syntaxTree.GetRoot();

            // 定位所有创建ErrorCodeException的对象初始化节点
            var exceptionCreations = root.DescendantNodes()
                .OfType<ObjectCreationExpressionSyntax>()
                .Where(oc => oc.Type.ToString() == "ErrorCodeException");

            foreach (var creation in exceptionCreations)
            {
                // 获取第一个参数(errorCode)
                var errorCodeArg = creation.ArgumentList.Arguments.FirstOrDefault();
                if (errorCodeArg == null)
                {
                    Assert.Fail($"文件{file}中发现格式错误的ErrorCodeException抛出:缺少errorCode参数");
                }

                // 校验参数是否为常量/字面量
                if (!IsConstantExpression(errorCodeArg.Expression))
                {
                    Assert.Fail($"文件{file}中发现非硬编码的errorCode:{errorCodeArg.Expression}");
                }

                // 解析错误码数值
                if (!int.TryParse(errorCodeArg.Expression.ToString(), out int errorCode))
                {
                    Assert.Fail($"文件{file}中无法解析errorCode:{errorCodeArg.Expression}");
                }

                // 检查错误码是否重复
                if (errorCodes.ContainsKey(errorCode))
                {
                    Assert.Fail($"错误码{errorCode}重复出现:\n首次出现位置:{errorCodes[errorCode]}\n二次出现位置:{file}");
                }
                else
                {
                    errorCodes.Add(errorCode, file);
                }
            }
        }
    }

    // 判断表达式是否为常量/字面量
    private bool IsConstantExpression(ExpressionSyntax expr)
    {
        // 直接字面量
        if (expr is LiteralExpressionSyntax)
            return true;

        // 常量字段引用(比如Constants.ErrorCode1)
        if (expr is MemberAccessExpressionSyntax)
        {
            // 如需更精准校验,可以结合语义分析(SemanticModel)判断成员是否为const
            return true;
        }

        // 排除变量、方法调用、计算表达式等运行时生成的值
        return false;
    }
}

额外优化建议

如果想在开发阶段就实时提示错误(不用等到跑单元测试),可以基于Roslyn写一个自定义代码分析器,在开发者写代码时就检查错误码的唯一性和硬编码要求,直接在VS中给出警告/错误提示,效率更高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 05:55:01