Hi,
I've recently been attempting to get the test project up and running for our project. It appears as though a previous colleague did attempt to setup the mocking of the database using an in-memory SQLite database using a custom DB context which appears to follow the steps outlined here https://aspnetboilerplate.com/Pages/Documents/Articles/Unit-Testing-with-Entity-Framework,-xUnit-Effort/index.html. Following on from that article, I've attempted to write some test cases for another part of our project and noticed that the linked article should support resolving the repository within the test class. However, when I attempt to resolve like this _siteJoinReportRepository = Resolve<ISiteJoinReportRepository>();
, I receive an object disposed exception with the following System.ObjectDisposedException Cannot access a disposed context instance. A common cause of this error is disposing a context instance that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling 'Dispose' on the context instance, or wrapping it in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
. I've tried to update the test base to something like this, which I thought by removing the using, would stop the context from being disposed but the issue still persists.
private void SeedTestData()
{
void NormalizeDbContext(XugoDbContext context)
{
context.EntityChangeEventHelper = NullEntityChangeEventHelper.Instance;
context.EventBus = NullEventBus.Instance;
context.SuppressAutoSetTenantId = true;
}
//Seed initial data for default tenant
AbpSession.TenantId = 1;
UsingDbContext(context =>
{
NormalizeDbContext(context);
new TestDataBuilder(context, 1).Create();
var repo = LocalIocManager.Resolve<EventReportRepository>();
var t = repo.GetTable();
});
}
protected IDisposable UsingTenantId(int? tenantId)
{
var previousTenantId = AbpSession.TenantId;
AbpSession.TenantId = tenantId;
return new DisposeAction(() => AbpSession.TenantId = previousTenantId);
}
protected void UsingDbContext(Action<XugoDbContext> action)
{
UsingDbContext(AbpSession.TenantId, action);
}
Please let me know if you need any further information or details.
Thanks.
8 Answer(s)
-
0
Hi @XugoWebTeam
Is it possible for us to test this on your project ? Or is it possible to provide a minimal reproduction project ?
-
0
Hi, thanks for the quick response. I've downloaded v11.3.0 of the ASP.NET CORE & Angular project and I was able to replicate the issue by simply adding this test class to the base project
using System.Linq; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Shouldly; using Xugo.Authorization.Users; using Xunit; namespace Xugo.Tests; public class UserManagerTests : AppTestBase { private IUserRepository _userRepository; public UserManagerTests() { _userRepository = Resolve<IUserRepository>(); } [Fact] public async Task Should_Get_Active_Users() { // Arrange var users = await _userRepository.InsertAsync(new User() { UserName = "test", IsActive = true, TenantId = 1, Name = "john", Surname = "smith", EmailAddress = "[email protected]", Password = "test", NormalizedUserName = "john", NormalizedEmailAddress = "[email protected]" }); // Act var activeUsers = _userRepository.GetAll() .Where(u => u.IsActive) .Select(u => u.Id) .ToListAsync(); // Assert await activeUsers.ShouldNotBeNull(); } }
This line doesn't appear to render correctly in the code block: _userRepository = Resolve<IUserRepository>();
-
0
Hi @ismcagdas, was this issue reproducible using the above?
-
0
Hi @XugoWebTeam,
I think this problem is related to the unit of work. You can use the following code for testing
await UsingDbContextAsync(async context => { var activeUsers = await context.Users .Where(u => u.IsActive) .Select(u => u.Id) .ToListAsync(); activeUsers.ShouldNotBeNull(); });
-
0
Unfortunately, I need to provide the repository as it's an argument of the static method I'm trying to test, it looks as though we should be able to resolve the repository as in the example here https://aspnetboilerplate.com/Pages/Documents/Articles/Unit-Testing-with-Entity-Framework,-xUnit-Effort/index.html#ArticleUsingRepositories . Could it be something to do with how it is registered in for the IocManager here?
public static void Register(IIocManager iocManager) { RegisterIdentity(iocManager); var builder = new DbContextOptionsBuilder<XugoDbContext>(); var inMemorySqlite = new SqliteConnection("Data Source=:memory:"); builder.UseSqlite(inMemorySqlite); iocManager.IocContainer.Register( Component .For<DbContextOptions<XugoDbContext>>() .Instance(builder.Options) .LifestyleSingleton() ); inMemorySqlite.Open(); new XugoDbContext(builder.Options).Database.EnsureCreated(); }
Otherwise, how do you think the unit of work may be causing the issue?
-
0
Hi @XugoWebTeam,
The following snippet may help solve your problem. If the problem persists, let us know.
public class UserManagerTests : AppTestBase { private readonly IUserRepository _userRepository; private readonly IUnitOfWorkManager _unitOfWorkManager; public UserManagerTests() { _userRepository = Resolve<IUserRepository>(); _unitOfWorkManager = Resolve<IUnitOfWorkManager>(); } [Fact] public async Task Should_Get_Active_Users() { // Arrange var users = await _userRepository.InsertAsync(new User() { UserName = "test", IsActive = true, TenantId = 1, Name = "john", Surname = "smith", EmailAddress = "[email protected]", Password = "test", NormalizedUserName = "john", NormalizedEmailAddress = "[email protected]" }); using var uow = _unitOfWorkManager.Begin(); var activeUsers = await _userRepository.GetAll() .Where(u => u.IsActive) .Select(u => u.Id) .ToListAsync(); activeUsers.ShouldNotBeNull(); // var activeUsers = _userRepository.GetAll() // .Where(u => u.IsActive) // .Select(u => u.Id) // .ToListAsync(); // // await activeUsers.ShouldNotBeNull(); } }
-
0
Yes, thank you, that appears to fix the issue. However, because I have a custom repository called like this within the method that I'm trying to test
var sitesdb = await siteJoinRepository.GetAllIncluding(c => c.Site, t => t.Site.SiteType).Where(t => t.XugoEventId == eventId).ToListAsync();
I imagine that I will have to wrap any method call which uses is a repository in a unit of work. Is there another way to handle this so that I don't need to do this?
-
0
Hi @XugoWebTeam,
Could you check this article? I think this attribute can solve your problem https://aspnetboilerplate.com/Pages/Documents/Unit-Of-Work#unitofwork-attribute