ASP.NET Core 1.0:如何在xUnit测试项目中注入DbContext?
问题:ASP.NET Core 1.0测试项目中如何注入ApplicationDbContext到仓储类?
我为ASP.NET Core 1.0应用创建了测试项目,其中仓储类的构造函数依赖ApplicationDbContext,现在想知道怎么在测试项目里获取并正确注入这个DbContext,完成单元测试。
我的ApplicationDbContext类代码如下:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser> { public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { } protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); } public DbSet<Category> Categories { get; set; } public DbSet<Product> Products { get; set; } public DbSet<ShoppingCartItem> ShoppingCartItems { get; set; } public DbSet<Order> Orders { get; set; } public DbSet<OrderDetail> OrderDetails { get; set; } }
初始的单元测试方法代码:
[Fact] public void ProductsGetAll() { //此处需要获取dbContext并注入 ProductRepository productRepository = new ProductRepository(dbContext); CategoryRepository categoryRepository = new CategoryRepository(dbContext); ProductController productController = new ProductController(productRepository, categoryRepository); }
我已经在测试类构造函数里添加上下文实例了:
ApplicationDbContext dbContext; public UnitTest1() { var options = new DbContextOptionsBuilder<ApplicationDbContext>() .UseInMemoryDatabase(databaseName: "FakeDatabase") .Options; dbContext = new ApplicationDbContext(options); }
不过测试方法还没完成,想知道接下来该怎么处理?
解决方案
你已经选对了核心方向——用内存数据库做单元测试,既不会污染真实数据库,又能快速模拟数据交互。接下来可以按以下步骤完善测试逻辑:
1. 初始化测试数据
在测试类构造函数或者单独的初始化方法里,给内存数据库填充测试用的Product和Category数据,这样测试时才有数据可以验证:
ApplicationDbContext dbContext; public UnitTest1() { var options = new DbContextOptionsBuilder<ApplicationDbContext>() .UseInMemoryDatabase(databaseName: "FakeDatabase") .Options; dbContext = new ApplicationDbContext(options); // 清空原有数据避免多测试干扰,再添加测试数据 dbContext.Products.RemoveRange(dbContext.Products); dbContext.Categories.RemoveRange(dbContext.Categories); dbContext.Categories.AddRange( new Category { Id = 1, Name = "电子产品" }, new Category { Id = 2, Name = "家居用品" } ); dbContext.Products.AddRange( new Product { Id = 1, Name = "手机", CategoryId = 1, Price = 3999 }, new Product { Id = 2, Name = "台灯", CategoryId = 2, Price = 99 } ); dbContext.SaveChanges(); }
2. 完善测试方法的验证逻辑
现在可以实例化仓储和控制器,调用目标测试方法(比如GetAll),然后验证返回结果是否符合预期:
[Fact] public void ProductsGetAll_ShouldReturnAllProducts() { // 实例化依赖的仓储与控制器 var productRepository = new ProductRepository(dbContext); var categoryRepository = new CategoryRepository(dbContext); var productController = new ProductController(productRepository, categoryRepository); // 调用控制器的GetAll方法(假设你的控制器有这个方法) var result = productController.GetAll(); // 验证返回结果的正确性 var okResult = Assert.IsType<OkObjectResult>(result); var returnedProducts = Assert.IsType<List<Product>>(okResult.Value); // 验证返回的产品数量和我们初始化的一致 Assert.Equal(2, returnedProducts.Count); // 可以进一步验证具体产品的属性 Assert.Equal("手机", returnedProducts.First(p => p.Id == 1).Name); }
3. 进阶:用DI容器模拟真实注入(可选)
如果你的项目本身依赖ASP.NET Core的DI容器,测试时也可以模拟这套逻辑,避免手动实例化所有依赖:
[Fact] public void ProductsGetAll_WithDI_ShouldReturnAllProducts() { // 构建测试用的服务容器 var services = new ServiceCollection(); services.AddDbContext<ApplicationDbContext>(options => options.UseInMemoryDatabase("FakeDatabase_DI")); services.AddScoped<IProductRepository, ProductRepository>(); services.AddScoped<ICategoryRepository, CategoryRepository>(); var serviceProvider = services.BuildServiceProvider(); // 从容器中获取仓储实例 using var scope = serviceProvider.CreateScope(); var productRepository = scope.ServiceProvider.GetRequiredService<IProductRepository>(); var categoryRepository = scope.ServiceProvider.GetRequiredService<ICategoryRepository>(); // 后续测试逻辑和之前一致 var productController = new ProductController(productRepository, categoryRepository); var result = productController.GetAll(); // 验证结果... }
这种方式更贴近真实项目的依赖注入模式,尤其当依赖关系复杂时,能减少手动实例化的工作量。
内容的提问来源于stack exchange,提问作者user9187119
相关产品推荐
相关产品推荐

