如何在xUnit Test项目中使用DbContext?

时间:2018-03-23 12:44:26

标签: c# asp.net unit-testing asp.net-core

我为我的核心1.0应用程序添加了一个测试项目。在其中我有在构造函数中使用dbContext的存储库。

如何在测试项目中访问此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()
        {
        //here i need to get acces to dbContext and inject it below

            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);
    }

和我的测试方法:

    [Fact]
        public void ProductsGetAll()
        {
            IProductRepository productRepository = new ProductRepository(dbContext);
            ICategoryRepository categoryRepository = new CategoryRepository(dbContext);
            ProductController productController = new ProductController(productRepository, categoryRepository);

            var result = productController.List("Pizza");

            var contentResult = result as ViewResult;
            var final = contentResult != null;
            Assert.False(final, "Shouldnt be null");

但现在我有一个错误:

Message: System.NullReferenceException : Object reference not set to an instance of an object.

2 个答案:

答案 0 :(得分:2)

我创建了一个interface,并将所有DbSets放入其中。

public class ApplicationDbContext : 
   IdentityDbContext<ApplicationUser>,  IDbContext
{
    ...
    public DbSet<Category> Categories { get; set; }
    ...
}

public interface IDbContext
{
   DbSet<Category> Categories { get; set; }
   ...
}

我的repository取决于接口而不是DbContext。

public class UserRepository : IUserRepository
{
   private readonly IDbContext _context;

   public UserRepository(IDbContext context)
   {
      _context = context;
   }
}

然后,我像this一样模拟IDbContext而不是实际的ApplicationDbContext。

var mockSet = MockHelper.GetMockDbSet(_users);
var mockDbContext = new Mock<IDbContext>();
mockDbContext.Setup(x => x.Users).Returns(mockSet.Object);
varmockDbContext = mockDbContext.Object;

更新

根据问题,您正在尝试模拟存储库。

如果是这样,我建议你创建 interfaces 并实现这些接口。然后将这些接口注入构造函数而不是注入具体类。例如。使用IProductRepository代替ProductRepository

然后你可以简单地模仿this -

var mockProductRepository = new Mock<IProductRepository>();
mockProductRepository.Setup(x => x.GetAllProductsAsync()).ReturnsAsync(_products);
var productController = new ProductController(mockProductRepository.Object,...);

答案 1 :(得分:0)

我不是.NET核心人员,但我猜您可以尝试使用内存数据库进行单元测试。

在较旧版本的EntityFramework中,您可以使用Effort,EF Core似乎已经解决了这个问题。我不确定这是否会立即起作用,因为我自己从未尝试过这个(再次,不是.net核心人),但你应该这样开始:

首先,添加包Microsoft.EntityFrameworkCore.InMemory 然后创建上下文并将其配置为使用In-Memory-DB

var options = new DbContextOptionsBuilder<ApplicationDbContext>()
    .UseInMemoryDatabase(databaseName: "pick_or_generate_a_unique_name_here")
    .Options;

var context = new ApplicationDbContext(options);

最后,将上下文注入您的存储库并在测试中使用它们

var productRepository = new ProductRepository(context);
var categoryRepository = new CategoryRepository(context);
var productController = new ProductController(productRepository, categoryRepository);

有关详细信息,请参阅此blogpostMSDN