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

如何为C# MVVC项目的Update方法编写单元测试

C# MVVM项目Update方法单元测试问题解决方案

现有代码的核心问题

现有Update方法无法直接编写单元测试的根本原因是代码与外部Oracle数据库强耦合,没有做依赖抽象,具体问题包括:

  • 方法内部直接实例化数据库连接类Conexion,无法替换为测试用的模拟连接
  • 直接依赖Oracle专属实现类(OracleConnection/OracleCommand),没有依赖.NET官方定义的数据库操作抽象接口
  • 数据访问逻辑与业务模型绑定,违反单一职责原则,单元测试无法脱离真实数据库运行

改造方案

第一步:抽象数据库操作接口

定义通用的数据操作接口,隔离业务代码与具体数据库实现:

public interface IDbHelper
{
    // 执行存储过程,返回受影响行数
    int ExecuteStoredProcedure(string procName, Dictionary<string, object> parameters);
}

第二步:实现Oracle专属的DbHelper

把原有数据库连接、执行命令的逻辑抽离到单独的实现类:

public class OracleDbHelper : IDbHelper
{
    public int ExecuteStoredProcedure(string procName, Dictionary<string, object> parameters)
    {
        using var conn = new Conexion().abrirConexion();
        using var cmd = new OracleCommand(procName, conn);
        cmd.CommandType = CommandType.StoredProcedure;
        foreach (var param in parameters)
        {
            cmd.Parameters.Add(param.Key, OracleDbType.NVarchar2).Value = param.Value;
        }
        var result = cmd.ExecuteNonQuery();
        conn.Close();
        return result;
    }
}

第三步:改造原有Model类,通过依赖注入传入IDbHelper

public class UsuarioInterno
{
    private readonly IDbHelper _dbHelper;
    // 构造函数注入依赖,单元测试时可传入模拟的IDbHelper实现
    public UsuarioInterno(IDbHelper dbHelper)
    {
        _dbHelper = dbHelper;
    }

    public string Name { get; set; }
    public string Surname { get; set; }

    public bool Update()
    {
        try
        {
            var parameters = new Dictionary<string, object>
            {
                {"i_name", this.Name},
                {"i_surname", this.Surname}
            };
            _dbHelper.ExecuteStoredProcedure("u_usuario_interno", parameters);
            return true;
        }
        catch (Exception)
        {
            return false;
        }
    }
}

单元测试编写示例

使用Mock框架(如Moq)模拟IDbHelper的行为,分别测试成功、异常场景:

using Moq;
using Xunit;

public class UsuarioInternoTests
{
    [Fact]
    public void Update_WhenExecuteSuccess_ReturnsTrue()
    {
        // 模拟IDbHelper执行成功的情况
        var mockDbHelper = new Mock<IDbHelper>();
        mockDbHelper.Setup(d => d.ExecuteStoredProcedure(It.IsAny<string>(), It.IsAny<Dictionary<string, object>>()))
                    .Returns(1);
        
        var usuario = new UsuarioInterno(mockDbHelper.Object)
        {
            Name = "张三",
            Surname = "李四"
        };

        var result = usuario.Update();
        
        Assert.True(result);
        // 验证参数传递是否正确
        mockDbHelper.Verify(d => d.ExecuteStoredProcedure("u_usuario_interno", 
            It.Is<Dictionary<string, object>>(p => 
                (string)p["i_name"] == "张三" && 
                (string)p["i_surname"] == "李四")), Times.Once);
    }

    [Fact]
    public void Update_WhenThrowException_ReturnsFalse()
    {
        // 模拟IDbHelper执行抛出异常的情况
        var mockDbHelper = new Mock<IDbHelper>();
        mockDbHelper.Setup(d => d.ExecuteStoredProcedure(It.IsAny<string>(), It.IsAny<Dictionary<string, object>>()))
                    .Throws(new Exception("数据库执行错误"));
        
        var usuario = new UsuarioInterno(mockDbHelper.Object);
        var result = usuario.Update();
        
        Assert.False(result);
    }
}

其他注意事项

  • 如果不想改动原有代码结构,也可以使用连接真实测试Oracle库的方式做集成测试,但这种测试不属于单元测试范畴,执行速度慢且依赖环境
  • 原有代码中conn的实例化可以优化,推荐用using语句自动释放连接,不需要手动调用Close方法,避免异常时资源泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 03:15:04