dimlucas
dimlucas

Reputation: 5141

Unit Tests vs Integration tests: Entity Framework Core In memory

I am currently working on an ASP.NET Core 2.0 Web API with EF Core 2.0. I plan to implement the Repository + UnitOfWork pattern and I've already created the abstractions, interfaces etc. Since I'm following a TDD approach I want to write tests on those interfaces before proceeding with the implementation.

The issue I'm facing is mostly related to semantics. I have created two projects in my solution, one for Unit Tests and one for Integration Tests. It's obvious to me that a test that also tests the database is not a unit test and should therefore be placed in the IntegrationTests project. The thing is though, that I am planning on using the EntityFrameworkCore.InMemory provider and boot up a fake in memory database for each test.

So every test should have this structure:

[TestClass]
public class GamesRepositoryTest
{
    AppDbContext _context;
    IGamesRepository _repository;

    public GamesRepositoryTest()
    {

    }

    [TestInitialize]
    public void Initialize()
    {
        DbContextOptionsBuilder<AppDbContext> builder = new DbContextOptionsBuilder<AppDbContext>().UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString());
        _context = new AppDbContext(builder.Options);
        _repository = new GamesRepository(_context);
    }

    [TestCleanup]
    public void Cleanup()
    {
        _context.Database.EnsureDeleted();
    }
}

So my question is, does EntityFrameworkCore.InMemory provide an adequate level of abstraction so that the above class can be considered a unit test or should I place it in the IntegrationTests project?

Upvotes: 5

Views: 4817

Answers (2)

ssmith
ssmith

Reputation: 8962

If you're testing with a real dbContext, whether it's hitting an RDBMS or an InMemory provider, it's an integration test. Why? Because you're testing that framework's implementation, not your code running in your method. Unit tests just test the "unit" of code they're running, typically a single method (and not its collaborators).

EF Core's InMemory provider is not 100% the same as testing with a real database. In fact, there are quite a few differences. It's mostly useful IME at development time to show how the system works with some seeded data and for functional tests that can verify that the whole system is working as expected (for example, using TestServer).

If your unit test project is meant to only contain unit tests, then it shouldn't have any dependencies on infrastructure-specific code like EF Core. It should typically only have a dependency on your own project(s) that are being tested, and whatever tools you're using for your tests (e.g. xUnit, Moq, etc.). If you find that you're pulling in infrastructure dependencies, odds are you're writing integration tests.

Upvotes: 4

Chris Pratt
Chris Pratt

Reputation: 239430

The new in-memory provider has confused the stuffing out of everyone. First and foremost let's just get its purpose cleared up: it's a test data provider. That's it. You could just as easily mock out the DbContext and return a static list or something. The in-memory provider just gives you an easier way to set up that test scaffold. It's not appropriate for integration testing, because you wouldn't actually use it in production. A proper integration test would hit a real facsimile of your production setup.

That said, the chief problem with the new in-memory provider for Entity Framework Core is that now people seem to be abusing it to test things that they shouldn't be testing. EF Core is already well-tested, so you should only be testing your application code. Again, just think of it like a mock without actually having to setup a mock. As long as you do that, you should be fine.

Based on all that, to answer your question, your tests should be unit tests, if for no other reason than if you're actually creating an integration test, you shouldn't be using the in-memory provider. Just make sure you're actually doing unit tests.

Upvotes: 22

Related Questions