In the first place is important to understand that for better testing in replacement to a relational database such SQL Server, In Memory database is not ideal.
Among the various limitations, it does not support foreign key constraints.
A better way to use an in-memory database is to use SQLite In-Memory mode.
Here is the code I used to setup the TestServer, Seed the Data and register the DB Context for the Dependency Injection:
TestServer
public class ApiClient {
private HttpClient _client;
public ApiClient()
{
var webHostBuilder = new WebHostBuilder();
webHostBuilder.UseEnvironment("Test");
webHostBuilder.UseStartup<Startup>();
var server = new TestServer(webHostBuilder);
_client = server.CreateClient();
}
public async Task<HttpResponseMessage> PostAsync<T>(string url, T entity)
{
var content = new StringContent(JsonConvert.SerializeObject(entity), Encoding.UTF8, "application/json");
return await _client.PostAsync(url, content);
}
public async Task<T> GetAsync<T>(string url)
{
var response = await _client.GetAsync(url);
response.EnsureSuccessStatusCode();
var responseString = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<T>(responseString);
}
}
Data Seeding (Helper class)
public class TestDataConfiguration
{
public static IMyContext GetContex()
{
var serviceCollection = new ServiceCollection();
IocConfig.RegisterContext(serviceCollection, "", null);
var serviceProvider = serviceCollection.BuildServiceProvider();
return serviceProvider.GetService<IMyContext>();
}
}
Data Seeding (Test class)
[TestInitialize]
public void TestInitialize()
{
_client = new ApiClient();
var context = TestDataConfiguration.GetContex();
var category = new Category
{
Active = true,
Description = "D",
Name = "N"
};
context.Categories.Add(category);
context.SaveChanges();
var transaction = new Transaction
{
CategoryId = category.Id,
Credit = 1,
Description = "A",
Recorded = DateTime.Now
};
context.Transactions.Add(transaction);
context.SaveChanges();
}
DB Context registration (In IocConfig.cs)
public static void RegisterContext(IServiceCollection services, string connectionString, IHostingEnvironment hostingEnvironment)
{
if (connectionString == null)
throw new ArgumentNullException(nameof(connectionString));
if (services == null)
throw new ArgumentNullException(nameof(services));
services.AddDbContext<MyContext>(options =>
{
if (hostingEnvironment == null || hostingEnvironment.IsTesting())
{
var connection = new SqliteConnection("DataSource='file::memory:?cache=shared'");
connection.Open();
options.UseSqlite(connection);
options.UseLoggerFactory(MyLoggerFactory);
}
else
{
options.UseSqlServer(connectionString);
options.UseLoggerFactory(MyLoggerFactory);
}
});
if (hostingEnvironment == null || hostingEnvironment.IsTesting())
{
services.AddSingleton<IMyContext>(service =>
{
var context = service.GetService<MyContext>();
context.Database.EnsureCreated();
return context;
});
} else {
services.AddTransient<IMyContext>(service => service.GetService<MyContext>());
}
}
The key is the URI file string used to create the SQLite connection:
var connection = new SqliteConnection("DataSource='file::memory:?cache=shared'");