Bob5421
Bob5421

Reputation: 9163

Dependency injection in Xunit project

I am working on an ASP.Net Core MVC Web application.

My Solution contains 2 projects:

I have added a reference to the application project in the Tests project.

What I want to do now is to write a class in the XUnit Tests project which will communicate with the database through entity framework.

What I was doing in my application project was to access to my DbContext class through constructor dependency injection.

But I cannot do this in my tests project, because I have no Startup.cs file. In this file I can declare which services will be available.

So what can I do to get a reference to an instance of my DbContext in the test class?

Upvotes: 35

Views: 44049

Answers (4)

Mohsen Esmailpour
Mohsen Esmailpour

Reputation: 11554

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

Upvotes: 45

elektromntr
elektromntr

Reputation: 1

You can to use package Microsoft.EntityFrameworkCore.InMemory

var _dbContextOptions = new DbContextOptionsBuilder<DbContext>().UseInMemoryDatabase(Guid.NewGuid().ToString()).Options;

And then

var context = new DbContext(_dbContextOptions);

Upvotes: 0

A. Wheatman
A. Wheatman

Reputation: 6396

You can use Xunit.DependencyInjection

Upvotes: 7

Paul Adam
Paul Adam

Reputation: 251

For unit tests you need to mock your context.

There is a great nuget package for mocking that is called Moq.

Some help to get you started:

public ClassName : IDisposable
{
    private SomeClassRepository _repository;
    private Mock<DbSet<SomeClass>> _mockSomeClass;

    public ClassName() 
    {
        _mockSomeClass = new Mock<DbSet<SomeClass>>();

        var mockContext = new Mock<IApplicationDbContext>();
        mockContext.SetupGet(c => c.SomeClass).Returns(_mockSomeClass.Object);

        _repository = new SomeClassRepository(mockContext.Object);
    }

    public void Dispose()
    {
        // Anything you need to dispose
    }

    [Fact]
    public void SomeClassTest()
    {
        var someClass = new SomeClass() { // Initilize object };

        _mockSomeClass.SetSource(new[] { someClass });

        var result = _repository.GetSomethingFromRepo( ... );

        // Assert the result
    }
}

For integration tests you do the same thing but the setup is:

_context = new ApplicationDbContext();

Make sure that your TestClass inherits from IDisposable (TestClass : IDisposable) so that you can dispose the context after each test.

https://xunit.github.io/docs/shared-context

Upvotes: 0

Related Questions