Unit Testing an EF data access layer
When writing a data access layer, chances are you want to write unit tests that verify the mapping, the calculated properties or the validation rules. If you happen to be using Entity Framework .Net 3.5, you may be out of luck if you want to write truly persistent ignorant unit tests that use mock objects.
You may consider structuring your production code to abstract the persistence yourself, as proposed in Diego Vega’s article. The problem, however, can become quite hairy if you are using the entity bag.
Another option is to use custom T4 template to generate the classes you need. But is it really worth struggling with so much custom code, while the EF .Net 4 brings all we need for free in VS2010 ?
In the meantime, as I needed a pattern for unit testing our domain logic in the data access layer, I went with the shortest path, which incidentally should provide a smooth transition to persistent ignorance promised with EF v4. For now, I stick to unit testing against a local SqlExpress store.
Using a single shared data store, however, requires a little bit of diligence. Unit tests can execute concurrently and in no particular order. So here is the guidance I would use for writing and executing such unit tests:
- Prior to running unit tests, the schema shall be redeployed from scratch to the local database.
- Unit tests shall not assume any data to be present in the store prior to execution.
If reference data is required by multiple tests, that data shall be (re)created by the [ClassInitialize] or [AssemblyInitialize] operations
  - Unit tests shall remain unaffected by existing database content.
If a unit test validates data creation, the data generated shall be unique (e.g. have a key containing a GUID or a random number). This makes unit tests more resilient against failures or prior tests.
  - Reference data created by [ClassInitialize] or [AssemblyInitialize] shall not be modified by the unit tests. If the test modifies data, that data shall be created for that specific unit test and shall have a unique key.� �Â
- Unit tests are permitted to leave residual data behind
E.g. a unit test initialization can leave reference data behind, which has the effect of speeding up execution on developer’s computer running unit tests repetitively without redeploying the schema.    - Tests shall only delete the data they created. They shall never try to delete data created by other or prior tests.
This would make the test setup or tear down more fragile as the links and deletion rules between entities or tables may have changed between builds   Â
The above list of bullet points obviously call for a class library helping with test data creation and clean-up: DataFactory, which I can cover in a future post if there is interest.
Great article Eric! Unit testing the database is always something I’ve struggled with. If you can spare any time to follow this up with other related articles, I’d be really grateful!
Kind regards,
James