【发布时间】:2021-02-08 12:26:42
【问题描述】:
我正在测试一个使用DbContext 的类。这个类得到一个IDbContextFactory 注入,然后用来得到一个DbContext:
protected readonly IDbContextFactory<SomeDbContext> ContextFactory;
public Repository(IDbContextFactory<SomeDbContext> contextFactory)
{
ContextFactory = contextFactory;
}
public List<T> Get()
{
using var db = ContextFactory.CreateDbContext();
return db.Set<T>().ToList();
}
我可以为 ONE 测试进行设置,但每次我想使用上下文时都必须调用 Mock<DbContextFactory>.Setup(f => f.CreateDbContext()) 方法。
这是一个例子:
var mockDbFactory = new Mock<IDbContextFactory<SomeDbContext>>();
mockDbFactory.Setup(f => f.CreateDbContext())
.Returns(new SomeDbContext(new DbContextOptionsBuilder<SomeDbContext>()
.UseInMemoryDatabase("InMemoryTest")
.Options));
var repository = new Repository<SomeEntity>(mockDbFactory.Object);
// non-existent id
Assert.IsNull(repository.Get(-1));
这很好用。但是,如果我添加另一个 repo 调用(如 Assert.DoesNotThrow(() => repository.Get(1);),我会得到
System.ObjectDisposedException: Cannot access a disposed context instance.
如果我再次拨打Mock<T>.Setup(),一切正常
var mockDbFactory = new Mock<IDbContextFactory<SomeDbContext>>();
mockDbFactory.Setup(f => f.CreateDbContext())
.Returns(new SomeDbContext(new DbContextOptionsBuilder<SomeDbContext>()
.UseInMemoryDatabase("InMemoryTest")
.Options));
var repository = new Repository<SomeEntity>(mockDbFactory.Object);
// non-existent id
Assert.IsNull(repository.Get(-1));
mockDbFactory.Setup(f => f.CreateDbContext())
.Returns(new SomeDbContext(new DbContextOptionsBuilder<SomeDbContext>()
.UseInMemoryDatabase("InMemoryTest")
.Options));
// pass
Assert.DoesNotThrow(() => repository.Get(1));
这是Get(int id) 方法:
public T Get(int id)
{
using var db = ContextFactory.CreateDbContext();
return db.Set<T>().Find(id);
}
据我了解,Mock 设置为返回
new SomeDbContext(new DbContextOptionsBuilder<SomeDbContext>()
.UseInMemoryDatabase("InMemoryTest")
.Options)
每次调用.CreateDbContext()。对我来说,这意味着它应该每次都返回一个新的上下文实例,而不是已经被处理的那个。但是,它看起来返回的是相同的已处理实例。
【问题讨论】:
标签: c# unit-testing asp.net-core entity-framework-core moq