Net Core: Execute All Dependency Injection in Xunit Test for Appservice, Repository, etc

Dependency injection in Xunit project

You can implement your own service provider to resolve DbContext.

public class DbFixture
{
public DbFixture()
{
var serviceCollection = new ServiceCollection();
serviceCollection
.AddDbContext<SomeContext>(options => options.UseSqlServer("connection string"),
ServiceLifetime.Transient);

ServiceProvider = serviceCollection.BuildServiceProvider();
}

public ServiceProvider ServiceProvider { get; private set; }
}

public class UnitTest1 : IClassFixture<DbFixture>
{
private ServiceProvider _serviceProvider;

public UnitTest1(DbFixture fixture)
{
_serviceProvider = fixture.ServiceProvider;
}

[Fact]
public void Test1()
{
using (var context = _serviceProvider.GetService<SomeContext>())
{
}
}
}

But bear in your mind using EF inside a unit test is not a good idea and it's better to mock DbContext.

The Anatomy of Good Unit Testing

Net Core: Execute Dependency Injection with Xunit for Unit of Work Pattern and DBContext

You are registering your services as transient ones, which means DI container creates new instanse each time service is needed to resolve or inject, so the instance of IUnitOfWork that is getting injected into IRepository<> isn't the same you're getting with GetService<IUnitOfWork>(). You can solve it by registering services with services.AddScoped, so that single instance of each service will be created per opened scope.

how to unit test asp.net core application with constructor dependency injection

Your controllers in .net core have dependency injection in mind from the start, but this does not mean you are required to use a dependency injection container.

Given a simpler class like:

public class MyController : Controller
{

private readonly IMyInterface _myInterface;

public MyController(IMyInterface myInterface)
{
_myInterface = myInterface;
}

public JsonResult Get()
{
return Json(_myInterface.Get());
}
}

public interface IMyInterface
{
IEnumerable<MyObject> Get();
}

public class MyClass : IMyInterface
{
public IEnumerable<MyObject> Get()
{
// implementation
}
}

So in your app, you're using the dependency injection container in your startup.cs, which does nothing more than provide a concretion of MyClass to use when IMyInterface is encountered. This does not mean it is the only way of getting instances of MyController however.

In a unit testing scenario, you can (and should) provide your own implementation (or mock/stub/fake) of IMyInterface as so:

public class MyTestClass : IMyInterface
{
public IEnumerable<MyObject> Get()
{
List<MyObject> list = new List<MyObject>();
// populate list
return list;
}
}

and in your test:

[TestClass]
public class MyControllerTests
{

MyController _systemUnderTest;
IMyInterface _myInterface;

[TestInitialize]
public void Setup()
{
_myInterface = new MyTestClass();
_systemUnderTest = new MyController(_myInterface);
}

}

So for the scope of unit testing MyController, the actual implementation of IMyInterface does not matter (and should not matter), only the interface itself matters. We have provided a "fake" implementation of IMyInterface through MyTestClass, but you could also do this with a mock like through Moq or RhinoMocks.

Bottom line, you do not actually need the dependency injection container to accomplish your tests, only a separate, controllable, implementation/mock/stub/fake of your tested classes dependencies.

Dependency Injection with XUnit and ASP.NET Core 1.0

Well, I don't think it is possible to access the container of the SUT. And to be honest I don't exactly understand why you'd want to. You will want complete control of your SUT. That means you want to provide your own dependencies to inject.

And that, you can!

_server = new TestServer(TestServer.CreateBuilder(null, app =>
{
app.UsePrimeCheckerMiddleware();
},
services =>
{
services.AddSingleton<IPrimeService, NegativePrimeService>();
services.AddSingleton<IPrimeCheckerOptions, PrimeCheckerOptions>();
}));

The CreateBuilder provides overloads for this. You'll need to provide configurations and app configurations for the same reasons (reason being you want complete control over your SUT). I followed this article to make the above example if you are interested. I could also upload the sample to my GitHub if you want?

Let me know if it helped.

Update
GitHub sample: https://github.com/DannyvanderKraan/ASPNETCoreAndXUnit

XUnit DI through overridden Startup file (.net core)

You can't use dependency injection on test classes. You can only let xunit inject special fixtures via constructor (see docs).

For Integration Testing you want to use the TestServer class from Microsoft.AspNetCore.TestHost package and a separate Startup.cs class (easier to setup configuration than inheritance imho).

public class TestStartup : Startup
{
public TestStartup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}

public IConfigurationRoot Configuration { get; }

public void ConfigureTestServices(IServiceCollection services)
{
services.Replace(ServiceDescriptor.Scoped<IService, MockedService>());
services.AddEntityFrameworkSqlite()
.AddDbContext<ApplicationDbContext>(
options => options.UseSqlite(connection)
);
}

public void Configure(IApplicationBuilder app)
{
// your usual registrations there
}
}

In your unit test project, you need to create an instance of the TestServer and perform the test.

public class DatasourceControllerTest
{
private readonly TestServer _server;
private readonly HttpClient _client;

public DatasourceControllerTest()
{
// Arrange
_server = new TestServer(new WebHostBuilder()
.UseStartup<TestStartup>());
_client = _server.CreateClient();
}

[Xunit.Theory,
InlineData(1)]
public async Task GetAll(int companyFk) {
// Act
var response = await _client.GetAsync($"/api/datasource/{companyFk}");
// expected result from rest service
var expected = @"[{""data"":""value1"", ""data2"":""value2""}]";

// Assert
// This makes sure, you return a success http code back in case of 4xx status codes
// or exceptions (5xx codes) it throws an exception
response.EnsureSuccessStatusCode();

var resultString = await response.Content.ReadAsStringAsync();
Assert.Equals(resultString, expectedString);
}
}

Now, when you call operations which write to the database, you can also check if the data is really written to the database:

[Xunit.Theory,
InlineData(1)]
public async Task GetAll(int companyFk) {
// Act
var response = await _client.DeleteAsync($"/api/datasource/{companyFk}");
// expected result from rest service

// Assert
response.EnsureSuccessStatusCode();

// now check if its really gone in the database. For this you need an instance
// of the in memory Sqlite DB. TestServer has a property Host, which is an IWebHost
// and it has a property Services which is the IoC container

var provider = _server.Host.Services;
var dbContext = provider.GetRequiredService<ApplicationDbContext>();

var result = await dbContext.YourTable.Where(entity => entity.Id == companyFk).Any();

// if it was deleted, the query should result in false
Assert.False(result);
}


Related Topics



Leave a reply



Submit