Reputation: 53
My DbSet is required. I'd like to create test using InMemoryDatabase. However when I instantiate context I'm getting an error
Error (active) CS9035
Required member 'TestContext.Users' must be set in the object initializer or attribute constructor.
This is my code:
public class TestContext : DbContext
{
public virtual required DbSet<User> Users { get; set; }
public TestContext(DbContextOptions<TestContext> options) : base(options)
{
}
}
public class UserTests
{
public UserTests()
{
var options = new DbContextOptionsBuilder<TestContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString())
.Options;
TestContext testContext = new TestContext(options);
}
}
I tried to set Users
property using initializer like this:
new TestContext(options) { Users = null }
but of course it sets DbSet
to null which is not what I want to achieve. I also inherited from the abstract class DbSet<User>
, but then I'd need to implement this class and I want to avoid that. I also tried to inherit context but inherited properties also need to be required.
Is it a way to instantiate context without explicitly setting DbSet
(please note that I'd like to keep required for DbSet
, I also don't want to use any mocking frameworks)?
Upvotes: 0
Views: 58
Reputation: 30340
I think you should be able to do this:
public virtual required DbSet<User> Users { get; set; } = default!;
For reference here's an example InMemory test database setup I use.
The DbContext
using a required
DbSet
.
public sealed class InMemoryTestDbContext
: DbContext
{
public required DbSet<DboWeatherForecast> WeatherForecasts { get; set; } = default!;
public InMemoryTestDbContext(DbContextOptions<InMemoryTestDbContext> options) : base(options) { }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<DboWeatherForecast>().ToTable("WeatherForecasts");
}
}
The services configuration and Test data loader.
services.AddDbContextFactory<InMemoryTestDbContext>(options
=> options.UseInMemoryDatabase($"TestDatabase-{Guid.NewGuid().ToString()}"));
var app = builder.Build();
// get the DbContext factory and add the test data
var factory = app.Services.GetService<IDbContextFactory<InMemoryTestDbContext>>();
if (factory is not null)
TestDataProvider.Instance().LoadDbContext<InMemoryTestDbContext>(factory);
The Singleton test data provider.
public sealed class TestDataProvider
{
public IEnumerable<DboWeatherForecast> WeatherForecasts => _weatherForecasts.AsEnumerable();
private List<DboWeatherForecast> _weatherForecasts = new List<DboWeatherForecast>();
public TestDataProvider()
{
this.Load();
}
private void Load()
{
var startDate = DateTime.Now;
var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };
_weatherForecasts = Enumerable.Range(1, 50).Select(index => new DboWeatherForecast
{
Date = startDate.AddDays(index),
Temperature = new(Random.Shared.Next(-20, 55)),
Summary = summaries[Random.Shared.Next(summaries.Length)]
}).ToList();
}
public void LoadDbContext<TDbContext>(IDbContextFactory<TDbContext> factory) where TDbContext : DbContext
{
using var dbContext = factory.CreateDbContext();
var dboWeatherForecasts = dbContext.Set<DboWeatherForecast>();
// Check if we already have a full data set
// If not clear down any existing data and start again
if (dboWeatherForecasts.Count() == 0)
dbContext.AddRange(_weatherForecasts);
dbContext.SaveChanges();
}
private static TestDataProvider? _provider;
public static TestDataProvider Instance()
{
if (_provider is null)
_provider = new TestDataProvider();
return _provider;
}
}
Upvotes: 0