【发布时间】:2021-04-02 12:29:48
【问题描述】:
我在单元测试时遇到了一个问题,如果我一次运行多个测试,DbContext 将丢失我在单元测试期间添加的记录,我认为这可能与服务的方式有关在我的ServiceCollection注册。
我有以下设置:
IUnitOfWork:
public interface IUnitOfWork : IDisposable
{
IUserRepository Users { get; }
int Complete();
}
工作单位
public class UnitOfWork : IUnitOfWork
{
private readonly MyDbContext _context;
public IUserRepository Users { get; }
public UnitOfWork(MyDbContext context,
IUserRepository userRepository)
{
_context = context;
Users = userRepository;
}
public void Dispose() => _context.Dispose();
public int Complete() => _context.SaveChanges();
}
用户存储库
public class UserRepository : Repository<User>, IUserRepository
{
public UserRepository(MyDbContext context) : base(context) { }
public MyDbContext MyDbContext => Context as MyDbContext;
public Task<User?> GetUserDetailsAsync(int userID)
{
var user = MyDbContext.Users.Where(user => user.Id == userID)
.Include(user => user.Emails)
.Include(user => user.PhoneNumbers).FirstOrDefault();
return Task.FromResult(user);
}
}
这是我的基本测试:
public abstract class BaseTest : IDisposable
{
protected ServiceProvider ServiceProvider { get; }
private MyDbContext MyDbContext { get; }
protected IUnitOfWork UnitOfWork { get; }
public BaseTest()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddScoped<IUserService, UserService>()
.AddScoped<IUnitOfWork, UnitOfWork>()
.AddScoped(typeof(IRepository<>), typeof(Repository<>))
.AddScoped<IOrganizationRepository, OrganizationRepository>()
.AddScoped<IExercisePostRepository, ExercisePostRepository>()
.AddScoped<IUserRepository, UserRepository>()
.AddTransient<IRestClient, RestClient>()
.AddAutoMapper(typeof(Startup).Assembly)
.AddDbContext<MyDbContext>(options =>
options.UseInMemoryDatabase("Core")
.EnableSensitiveDataLogging());
ServiceProvider = serviceCollection.BuildServiceProvider();
SpotcheckrCoreContext = ServiceProvider.GetRequiredService<MyDbContext>();
MyDbContext.Database.EnsureCreated();
UnitOfWork = ServiceProvider.GetRequiredService<IUnitOfWork>();
}
public void Dispose()
{
MyDbContext.Database.EnsureDeleted();
UnitOfWork.Dispose();
}
}
样本测试:
public class UserServiceTests : BaseTest
{
private readonly IUnitOfWork UnitOfWork;
private readonly IUserService Service;
public UserServiceTests()
{
UnitOfWork = ServiceProvider.GetRequiredService<IUnitOfWork>();
Service = ServiceProvider.GetRequiredService<IUserService>();
}
[Fact]
public async void GetUserAsync_WithValidUser_ReturnsUser()
{
var user = new User
{
FirstName = "John",
LastName = "Doe"
};
UnitOfWork.Users.Add(user);
UnitOfWork.Complete();
var result = await Service.GetUserAsync(user.Id);
Assert.Equal(user.Id, result.Id);
}
}
如果我自己运行这个测试,那么它将正确通过,我可以在存储库中看到用户。但是,如果我使用其他测试运行它并进行调试,那么一旦我在存储库中检查 UnitOfWork.Users,该用户就会丢失,但我确实在测试中的 UnitOfWork.Users 中看到它。
这里的正确方法是什么?
编辑 1:
尝试了其他一些更改,但还没有运气。调整UnitOfWork 以接收每个存储库的接口并将它们注册到BaseTest 作为范围服务。还尝试将BaseTest 标记为实现IDisposable,然后执行:
public void Dispose()
{
MyDbContext.Database.EnsureDeleted();
UnitOfWork.Dispose();
}
在服务层我会看到用户很好,但是一旦我进入存储库层,我就会失去用户:/我怀疑它与依赖注入 AddScoped 和 AddTransient 有关以及所有这些如何与运行多个单元测试一起工作。
编辑 2:
尝试了更多的东西...在每个测试类上使用了IClassFixture<BaseTest>,然后确保每个测试类都实现了IDisposable,在那里我将确保删除上下文数据库;还确保在测试类构造函数中创建了它。有了这个,我最终得到了以下错误:
The instance of entity type cannot be tracked because another instance with the same key value for {'Id'} is already being tracked
所以我添加了.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking),但问题仍然存在。
这设置起来很烦人。
【问题讨论】:
标签: .net-core entity-framework-core xunit