Skip to content

Instantly share code, notes, and snippets.

@alistairmgreen
Created February 10, 2017 22:11
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alistairmgreen/ca3f7baddb737fd91e6bf7399ba6deeb to your computer and use it in GitHub Desktop.
Save alistairmgreen/ca3f7baddb737fd91e6bf7399ba6deeb to your computer and use it in GitHub Desktop.
Entity Framework Integration Testing

Writing Tests for Entity Framework

Do You Really Want Unit Tests For Everything?

The business layer of an application should generally access the database through an abstraction such as a service, command or query class. This has two benefits:

  • It expresses our intent whilst hiding the details of the database schema and implementation.
  • We can mock the service / command / query in order to write unit tests for the business logic: "If the query returns x, then y should happen."

So far, so good. But how should we test-drive the development of the service class?

It is tempting to make the service depend on an abstract repository or unit of work so that it too is isolated from the database. However, this strategy can ultimately result in unit tests which simply verify that abstraction A calls the right methods on abstraction B, which calls the right methods on abstraction C and so on. At this point we are creating classes that don't do any actual work themselves, just so that we can create tests for the sake of having tests.

Bear in mind that:

  • Entity Framework provides an abstraction that hides the underlying database provider. Our code does not need to know whether it is talking to SQL Server, Oracle, SQLite or some other obscure database system.
  • The Entity Framework database context is effectively a unit-of-work implementation. Any changes that we make are applied atomically when we call SaveChanges().
  • If Entity Framework is hidden behind some sort of generic IRepository<T>, then it becomes more difficult to use it efficiently. If the repository does not know what its output is being used for, then it cannot tell which foreign key references should be eagerly loaded and which ones should not.
  • If our service needs to perform a complicated query, then unit tests cannot tell us whether the query is correct. The only way to be sure is to run the query against a database with known contents.

The simplest way to implement our service, then, is to allow it to use the Entity Framework context directly and accept that it can only be tested at the integration level. This is not necessarily a bad thing if we can find an efficient and repeatable way to run the integration tests.

Integration Testing With An In-Memory Database

Effort is a library that connects Entity Framework to an in-memory database. This makes it easy (at least in theory) to write integration tests for your data access layer which always start from a known database state, and don't require a real database server.

You probably want the Effort.EF6 package from NuGet.

More info:

Acceptance Testing With A Real Database

Respawn could be helpful here. It provides functions for resetting a database back to a known state by deleting data from tables.

See also the blog post "Powerful Integration Testing" at Los Techies.

@iant-ee
Copy link

iant-ee commented Jul 5, 2021

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment