Edward
Edward

Reputation: 30056

XUnit Test DbContext did not dispose

I am implementing a XUnit test for DbContext, it seems the DbContext did not dispose correctly. When I debug the first test, it works, but on the second test, an error listAds already added is thrown.

After adding a watch, in the second test, _context is null, but it has values for Advertisements before _context.Advertisements.AddRange(listAds); is called.

public class AdsServiceTest: IDisposable
{
    private readonly DbContextOptions<SensingSiteDbContext> _options;
    private readonly SensingSiteDbContext _context;
    private readonly AdsService _AdsService;

    public AdsServiceTest()
    {
        //initialize db options
        _options = new DbContextOptionsBuilder<SensingSiteDbContext>()
            .UseInMemoryDatabase()
            .Options;

        //get service
        _context = new SensingSiteDbContext(_options);

        //initialize dbcontext
        List<Ads> listAds = new List<Ads>() {
            new Ads(){  Id=1,AdsName="Ads1", Deleted=false},
            new Ads(){  Id=2,AdsName="Ads2", Deleted=false},
            new Ads(){  Id=3,AdsName="Ads3", Deleted=false}
        };

        //In the second test method, it throw errors, listAds already exist in 
        _context.Advertisements.AddRange(listAds);
        _context.SaveChanges();
        BaseLib.SSDbContext<Ads, AdsService> ssDbContent = new BaseLib.SSDbContext<Ads, AdsService>(_context);
        _AdsService = ssDbContent.GetService((x, y) => new AdsService(x, y));

    }

    public void Dispose()
    {
        _context.Dispose();            
    }

    [Theory]
    [InlineData(1)]
    public void FindById(int id)
    {
        Ads adsResult = _AdsService.FindById(id);
        Ads adsTarget = _context.Advertisements.Find(id);
        Assert.Equal(adsResult.AdsName, adsTarget.AdsName);
        //Assert.True(adsTarget.Equals(adsResult));
    }

    [Fact]
    public void GetAll()
    {
        var adsResult = _AdsService.GetAll();
        var adsTarget = _context.Advertisements.ToList();
        Assert.Equal(adsResult.Count(),adsTarget.Count());
        //Did not work all the time
        //Assert.True(adsTarget.Equals(adsResult));
    }
}

Upvotes: 3

Views: 3939

Answers (1)

Dmitry
Dmitry

Reputation: 16825

Context is disposed, but not "in-memory database" itself.

That's "by design" to allow you to test scenarios where classes you testing are creating it's own instance of DBContext - you can't prepare data for them otherwise.

You have two possibilities:

  1. Create "different databases" for each test with databaseName with code like .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())

  2. Force database destroy/recreate with context.Database.EnsureDeleted() after creation (or in Dispose).

For your test class method 2 looks more suitable, but it's up to you.

Docs: https://learn.microsoft.com/en-us/ef/core/miscellaneous/testing/in-memory

Upvotes: 11

Related Questions