Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NUnit Entity Framework integration test dependency injection issue with .NET Core

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>());
    }
}
like image 338
Andy Furniss Avatar asked Mar 18 '18 17:03

Andy Furniss


People also ask

Can Nunit be used for integration testing?

ASP.NET Core has an extremely useful integration testing framework, in the form of the NuGet package Microsoft.

Does .NET Core have dependency injection?

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.

Which package component can be added for integration testing of the .NET Core API applications?

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.


2 Answers

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>());
    }
}
like image 166
Andy Furniss Avatar answered Nov 04 '22 21:11

Andy Furniss


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.

Basic Example

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.

like image 20
NightOwl888 Avatar answered Nov 04 '22 21:11

NightOwl888