Page 16 - MSDN Magazine, April 2017
P. 16

Data Points JULIE LERMAN
Tips for Building Tests with EF Core and Its InMemory Provider
When creating automated tests against methods that trigger data- base interaction, there are times when you truly want to see what’s happening in the database, and other times when the database interaction isn’t at all relevant to your test’s assertion. The new EF Core InMemory provider can prove useful in the latter case. In this article I’ll provide an introduction to this handy tool and share some tips and tricks about creating automated tests with EF Core that I’ve discovered while learning to use it myself.
In cases where the database effort isn’t important to the test result, unnecessary calls to the database can put a strain on per- formance or even cause inaccurate test results. For example, the amount of time it takes to talk to the database—or drop and recreate a test database—can hold up your tests. Another concern is if there’s a problem with the database itself. Perhaps network latency or a momentary hiccup causes a test to fail only because the database is unavailable, not as a result of a failure in the logic the test is attempting to assert.
Microsoft has created another provider—not to persist to a database, but to temporarily persist to memory.
We’ve long sought ways to minimize these side effects. Fakes and mocking frameworks are common solutions. These patterns allow you to create in-memory representations of the data store, but there’s a lot involved in setting up their in-memory data and behavior. Another approach is to use a lighter-weight database for testing than you’re targeting in production, such as a PostgreSQL or SQLite database, rather than, for example, a SQL Server database you use for your production data store. Entity Framework (EF) has always allowed for targeting different databases with a single model thanks to the various providers available. However, nuanced dif- ferences in database functionality can cause you to hit issues where this won’t always work (though it’s still a good option to keep in your toolbox). Alternatively, you could use an external tool, such as the open source EFFORT extension (github.com/tamasflamich/effort),
which magically provides an in-memory representation of the data store without the setup needed for fakes or mocking frameworks. EFFORT works with EF 4.1 through EF6, but not EF Core.
There are already a number of database providers for EF Core. Microsoft includes the SQL Server and SQLite providers as part of the family of EntityFrameworkCore APIs. There are also providers for SQLCE and PostgreSQL, respectively maintained by MVPs Erik Eilskov Jensen and Shay Rojansky. And there are third-party com- mercially available providers. But Microsoft has created another provider—not to persist to a database, but to temporarily persist to memory. This is the InMemory provider: Microsoft. EntityFrame- workCore.InMemory, which you can use as a quick way to provide a stand-in for an actual database in many testing scenarios.
Readying the DbContext
for the InMemory Provider
Because your DbContext will sometimes be used to connect to a true data store and sometimes to the InMemory provider, you want to set it up to be flexible with respect to providers, rather than dependent on any particular provider.
When instantiating a DbContext in EF Core, you have to include DbContextOptions that specify which provider to use and, if needed, a connection string. UseSqlServer and UseSqlite, for example, require that you pass in a connection string, and each provider gives you access to the relevant extension method. Here’s how this looks if done directly in the DbContext class OnConfiguring method, where I’m reading a connection string from an application config file:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { var settings = ConfigurationManager.ConnectionStrings;
var connectionString = settings["productionDb"].ConnectionString; optionsBuilder.UseSqlServer(connectionString);
}
A more flexible pattern, however, is to pass a pre-configured DbContextOptions object into the constructor of the DbContext:
public SamuraiContext(DbContextOptions<SamuraiContext> options) :base(options) { }
EF Core will pass those pre-configured options into the under- lying DbContext and apply them for you.
With this constructor in place, you now have a way to specify different providers (and other options, such as a connection string) on the fly from the logic that’s using the context.
If you’re using some type of Inversion of Control (IoC) container in your application, such as StructureMap (structuremap.github.io) or the services built into ASP.NET Core, you have the ability to
Code download available at msdn.com/magazine/0417magcode.
12 msdn magazine













































































   14   15   16   17   18