Database Reference
In-Depth Information
The Test project now has three unit tests that exercise the following business rules:
A passenger cannot have more than one reservation for a scheduled departure.
The arrival date and time for a schedule must be after the departure date and time.
The departure location cannot be the same as the arrival location.
How It Works
With quite a lot of code, we've managed to build a complete solution that includes an interface (IReservationContext)
that we can use to abstractly reference a DbContext, a fake DbSet ( FakeDbSet<T> ), a fake DbContext
(FakeReservationContext), and a small set of unit tests. We use the fake DbContext so that our tests don't interact with
the database. The purpose of the tests is to validate our business rules, not to test the database interactions.
One key to the solution is that we created a simplified repository that managed the inserting and selecting of our
objects. The constructor for this repository takes an IReservationContext. This subtle abstraction allows us to pass in
an instance of any class that implements IReservationContext. To test our domain objects, we pass in an instance of
FakeReservationContext. To allow our domain objects to be persisted to the database, we would pass in an instance of
our real DbContext: EFRecipesEntities .
We need the DbSets returned by our fake DbContext to match the DbSets returned by the real
EFRecipesEntities DbContext. To do this, we changed the T4 template that generates the context to return
IDbSet<T> in place of DbSet<T> . We made sure our fake DbContext also returned DbSets of type IDbSet<T> . With this
in place, we implemented our FakeDbSet<T> and derived it from IDbSet<T> .
In the Tests project, we set up the tests by creating a Reservation Repository based on an instance of the
FakeReservationContext. The unit tests interact with the FakeReservationContext in place of the real DbContext.
Best Practice
There are two testing approaches that seem to work well for Entity Framework: Define a repository interface that
both the real repository and one or more “testing” repositories implement. By hiding all of the interactions with the
persistence framework behind the implementation of the repository interface, there is no need to create fake versions
of any of the other infrastructure parts. This can simplify the implementation of the testing code, but it may leave parts
of the repository itself untested.
Define an interface for the DbContext that exposes properties of type IDbSet<T> and a SaveChanges() method,
as we have done in this recipe. The real DbContext and all of the fake DbContexts must implement this interface.
Using this approach, you don't need to fake the entire repository, which may be difficult in some cases. Your fake
DbContexts don't need to mimic the behavior of the entire DbContext class; that would be a real challenge. You do
need to limit your code to just what is available on the interfaces.
8-9. Testing a Repository Against a Database
Problem
You want to test your repository against the database.
This type of recipe is often used when integration testing of whole-data access functionality has to be performed.
Solution
You have created a repository that manages all of the queries, inserts, updates, and deletes. You want to test this repository
against a real instance of the underlying database. Suppose that you have a model like the one shown in Figure 8-10 .
Because we will create and drop the database during the tests, let's start from the beginning in a test database.
 
Search WWH ::




Custom Search