简体   繁体   中英

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>());
    }
}

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.

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM