Mocking a DBContext for Testing
The easiest means to mock a data context for testing, is to use an in-memory database.
An in-memory database is known by its string-name within a process. Each data context accessing the database instance must use its name, via options.
A few things are needed to mockup a dbcontext for testing:
-
Entity class or classes
-
Data Context class with DbSet for each entity class
-
String name of the database
-
Data Context builder options for an in-memory database
-
Creating a Context Instance
-
Entity Class
At least one entity class. This can be any simple entity class with an Id property, such as the following:
public class TestClass
{
public int Id { get; set; }
public string Val1 { get; set; }
public int Val2 { get; set; }
}
2. Data Context
The data context class requires a DbSet for each test class. This can be as simple as the following:
public class TestDbContext : DbContext
{
public TestDbContext([NotNullAttribute] DbContextOptions options) : base(options)
// public cDBDContext_Base() : base()
{
}
public TestDbContext() : base()
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//base.OnModelCreating(modelBuilder);
}
public override int SaveChanges()
{
return base.SaveChanges();
}
public DbSet<TestClass> TestData { get; set; }
}
3. Database Name
This is the string-name of the database.
Any context using this name will reach the same in-memory database.
4. Data Context Builder Options
The following is a simple builder options for creating a data context to an in-memory database of a given name:
var options = new DbContextOptionsBuilder<GenericRepositoryEF_Tests.TestDbContext>()
.UseInMemoryDatabase(databaseName: stringdatabasename)
.Options;
5. Creating a data context instance
The following is a method to create a data context instance and populate it with test data:
string dbname = "testdatabase";
// Create an options instance to give us a connection to the named in-memory database.
var options = new DbContextOptionsBuilder<GenericRepositoryEF_Tests.TestDbContext>()
.UseInMemoryDatabase(databaseName: dbname)
.Options;
// Insert seed data into the database using one instance of the context...
using (var context = new GenericRepositoryEF_Tests.TestDbContext(options))
{
// Populate the list...
for(int x = 0; x < 1000; x++)
{
GenericRepositoryEF_Tests.TestClass tc = new TestClass();
tc.Val1 = x.ToString();
tc.Val2 = x;
context.TestData.Add(tc);
}
context.SaveChanges();
}
6. Any subsequent context instance with the same database string name, will have access to the seeded data above.
Meaning, a second data context, created with the same options, can access the seed data, generated by the above code:
// Create an options instance to give us a connection to the named in-memory database.
var options1 = new DbContextOptionsBuilder<GenericRepositoryEF_Tests.TestDbContext>()
.UseInMemoryDatabase(databaseName: "testdatabase")
.Options;
// Use a clean instance of the context to access data...
using (var context = new GenericRepositoryEF_Tests.TestDbContext(options1))
{
// Now, do a simple query for some portion of the list...
var query = from b in context.TestData
//where b.Val2 > 1000
select b;
var res = query.ToList();
}
No Comments