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

如何在单元测试中跳过构造函数中的数据库操作?

解决单元测试时跳过构造函数数据库操作的方案

方案一:依赖注入解耦(推荐)

把数据库操作逻辑抽象成接口,让OrderVM通过构造函数依赖这个接口,测试时注入模拟实现,彻底隔离数据库依赖。

  1. 定义产品数据访问接口
public interface IProductRepository
{
    List<Product> GetAllProducts();
}
  1. 实现生产环境用的仓库类
public class ProductRepository : IProductRepository
{
    public List<Product> GetAllProducts()
    {
        using (var db = new DatabaseContext())
        {
            return db.Products_t.ToList();
        }
    }
}
  1. 修改OrderVM的构造函数,支持依赖注入
public class OrderVM
{
    public ObservableCollection<Product> Products_o { get; set; }
    public decimal SubTotal { get; set; }
    public decimal Tax { get; set; }

    // 生产环境默认构造函数,自动注入真实仓库
    public OrderVM() : this(new ProductRepository())
    {
    }

    // 测试专用构造函数,接受自定义仓库实现
    public OrderVM(IProductRepository productRepo)
    {
        var productList = productRepo.GetAllProducts();
        Products_o = new ObservableCollection<Product>(productList);
    }

    public void calTax()
    {
        Tax = SubTotal * 5 / 100;
    }
}
  1. 单元测试中使用模拟仓库(以Moq为例)
public class UnitTest1
{
    [Fact]
    public void Calculate_Tax()
    {
        // 模拟仓库,返回空列表即可,因为calTax不依赖产品数据
        var mockRepo = new Mock<IProductRepository>();
        mockRepo.Setup(repo => repo.GetAllProducts()).Returns(new List<Product>());

        var order = new OrderVM(mockRepo.Object);
        order.SubTotal = 100;
        order.calTax();
        order.Tax.Should().Be(5);
    }
}

方案二:添加测试专用构造函数(快速临时方案)

如果不想大规模重构,给OrderVM加一个内部构造函数,跳过数据库初始化逻辑,测试项目通过InternalsVisibleTo访问这个构造函数。

  1. 修改OrderVM,添加测试构造函数
public class OrderVM
{
    public ObservableCollection<Product> Products_o { get; set; }
    public decimal SubTotal { get; set; }
    public decimal Tax { get; set; }

    public OrderVM()
    {
        using (var db = new DatabaseContext())
        {
            var list = db.Products_t.ToList();
            Products_o = new ObservableCollection<Product>(list);
        }             
    }

    // 测试专用构造函数,标记为内部访问
    internal OrderVM(bool skipDbInit)
    {
        // 初始化空集合,避免空引用异常
        Products_o = new ObservableCollection<Product>();
    }

    public void calTax()
    {
        Tax = SubTotal * 5 / 100;
    }
}
  1. 在主项目的.csproj中添加配置,允许测试项目访问内部成员
<ItemGroup>
  <InternalsVisibleTo Include="你的测试项目名称" />
</ItemGroup>
  1. 编写单元测试
public class UnitTest1
{
    [Fact]
    public void Calculate_Tax()
    {
        // 使用测试专用构造函数,跳过数据库操作
        var order = new OrderVM(skipDbInit: true);
        order.SubTotal = 100;
        order.calTax();
        order.Tax.Should().Be(5);
    }
}

方案三:使用内存数据库(适合需要初始化产品数据的场景)

如果测试时需要Products_o有真实结构但不想依赖物理数据库,可以用EF Core的内存数据库替代。

  1. 修改DatabaseContext,支持传入DbContextOptions
public class DatabaseContext : DbContext
{
    public DatabaseContext() { }

    public DatabaseContext(DbContextOptions<DatabaseContext> options) : base(options) { }

    public DbSet<Product> Products_t { get; set; }
}
  1. 单元测试中创建内存数据库
public class UnitTest1
{
    [Fact]
    public void Calculate_Tax()
    {
        // 配置内存数据库
        var options = new DbContextOptionsBuilder<DatabaseContext>()
            .UseInMemoryDatabase(databaseName: "Test_OrderDb")
            .Options;

        // 提前创建表结构
        using (var db = new DatabaseContext(options))
        {
            db.Database.EnsureCreated();
        }

        // 此时创建OrderVM会使用内存数据库,不会报错
        var order = new OrderVM();
        order.SubTotal = 100;
        order.calTax();
        order.Tax.Should().Be(5);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 23:47:30