I have just started looking into .NET Core with Entity Framework. I have previously used .NET Framework with Ninject but I'm now trying to use the DI built into .NET Core.
I have a TestBase
class which my tests will derive from. I want this class to be responsible for creating and deleting a test database using [OneTimeSetUp]
and [OneTimeTearDown]
. The problem is that I don't seem to be able to figure out how to gain access to my DI services in the setup and teardown methods. These methods cannot have parameters and my TestBase
class must have a parameterless constructor so I can't get them from there either.
[SetUpFixture]
public partial class TestBase
{
protected IEFDatabaseContext DataContext { get; set; }
public TestBase(IEFDatabaseContext dataContext)
{
this.DataContext = dataContext;
}
[OneTimeSetUp]
public void TestInitialise()
{
this.DataContext.Database.EnsureCreated();
}
[OneTimeTearDown]
public void TestTearDown()
{
this.DataContext.Database.EnsureDeleted();
}
}
The above gives the following error:
TestBase
does not have a default constructor.
I may well be going about this the wrong way but this is how I've always done things in the past so please let me know if there is a better method when using .NET Core DI.
Startup
class for reference:
public class Startup
{
private readonly IConfiguration config;
public Startup(IConfiguration config)
{
this.config = config;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<TestDataContext>(
options => options.UseSqlServer(this.config.GetConnectionString("TestConnectionString")),
ServiceLifetime.Singleton);
services.AddScoped<IEFDatabaseContext>(provider => provider.GetService<TestDataContext>());
}
}
ASP.NET Core has an extremely useful integration testing framework, in the form of the NuGet package Microsoft.
ASP.NET Core supports the dependency injection (DI) software design pattern, which is a technique for achieving Inversion of Control (IoC) between classes and their dependencies. For more information specific to dependency injection within MVC controllers, see Dependency injection into controllers in ASP.NET Core.
The test web host (TestServer) is available in a NuGet component as Microsoft. AspNetCore. TestHost. It can be added to integration test projects and used to host ASP.NET Core applications.
Thanks to NightOwl for pointing me in the right direction. A combination of the Microsoft article on integration testing and the possible dupe question led me to the following solution.
By using the TestServer
from Microsoft.AspNetCore.TestHost
I am able to access the DI ServiceProvider
built in Startup
.
TestBase:
public partial class TestBase
{
protected readonly TestServer server;
protected readonly IEFDatabaseContext DataContext;
public TestBase()
{
this.server = new TestServer(new WebHostBuilder().UseStartup<Startup>());
this.DataContext = this.server.Host.Services.GetService<IEFDatabaseContext>();
}
[OneTimeSetUp]
public void TestInitialise()
{
this.DataContext.Database.EnsureCreated();
}
[OneTimeTearDown]
public void TestTearDown()
{
this.DataContext.Database.EnsureDeleted();
}
}
Startup:
public class Startup
{
private readonly IConfiguration config;
public Startup(IConfiguration config)
{
this.config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
}
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<TestDataContext>(
options => options.UseSqlServer(this.config.GetConnectionString("TestConnectionString")),
ServiceLifetime.Singleton);
services.AddScoped<IEFDatabaseContext>(provider => provider.GetService<TestDataContext>());
}
}
Integration testing ASP.NET Core is well covered by the Microsoft documentation.
Basically, you need to install the Test Host project from NuGet Microsoft.AspNetCore.TestHost
, then use it to launch the web environment within NUnit.
public class TestClass
{
private TestServer _server;
private HttpClient _client;
[OneTimeSetUp]
public void SetUp()
{
// Arrange
_server = new TestServer(new WebHostBuilder()
.UseStartup<Startup>());
_client = _server.CreateClient();
}
[OneTimeTearDown]
public void TearDown()
{
_server = null;
_client = null;
}
[Test]
public async Task ReturnHelloWorld()
{
// Act
var response = await _client.GetAsync("/");
response.EnsureSuccessStatusCode();
var responseString = await response.Content.ReadAsStringAsync();
// Assert
Assert.Equal("Hello World!",
responseString);
}
}
With the TestServer
it is possible to intervene with the DI configuration and/or the IConfiguration
to substitute fakes in the configuration. See Reconfigure dependencies when Integration testing ASP.NET Core Web API and EF Core.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With