35

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

My Solution contains 2 projects:

  • One for the application and
  • A second project, dedicated to unit tests (XUnit).

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?

1
  • Try this xunit di support built into xunit framework: nuget.org/packages/Xunit.Di, so that you can inject services dependencies the same way as you do for any other applications. Commented Oct 3, 2021 at 12:00

4 Answers 4

45

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

Sign up to request clarification or add additional context in comments.

15 Comments

What is DatabaseSeeder ? Should i put DbFixture in a Service subfolder ?
Oops copy paste mistake. You can put DbFixture anywhere inside test project. I create TestSetup or TestInfrastructure folder and put such classes in these folders.
Instead of your line with AddEntityFrameworkSqlServer, i am using this: serviceCollection.AddDbContext<BDDContext>(options => options.UseSqlServer("connection string") Is there a big difference ?
No both works fine and AddEntityFrameworkSqlServer registers additional services.
@Matt I fixed the broken link.
|
7

You can use Xunit.DependencyInjection

2 Comments

Expanding on what this does and why it's better than other approaches would be super useful here. Also adding a small sample demonstrating how it looks when used would be great .
stackoverflow.com/questions/63269460/… Working through the problem
0

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

Comments

-1

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

1 Comment

There's no SetUp, atrribute in xunit. Use constructor instead.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.