dotnet / dotnet/efcore

Create an IDatabaseFacade interface for mocking purposes in business logic

Open
#28,397 10 comments 1 reaction 0 assignees View on GitHub
area-dbcontext customer-reported
Dominant language
C#
Stars
14.8k
Forks
3.4k
PR merge metrics
PR metrics pending

Description

I have a piece of business logic that goes as follows (Obfuscated pseudo code because I cannot share it literally)

```C#
public async Task SomeFunction(CancelationToken ct)
{
await DoSomeCallsOnExternalService1(ct);
var transaction = await _injectedContext.Database.BeginTransactionAsync(ct);
await DoSomeDatabaseStuff();
try
{
await DoSomeCallsOnExternalService2(ct);
}
catch (ApiException e)
{
Logger.Error(e);
await transaction.RollbackAsync(ct);
await RollbackCallsOnExternalService1(ct);
}
}
```

This is a crucial piece of business logic where unit testing, if the rollback is correctly invoked, is very important. Sadly enough, there are EF calls in it. Why does that make me sad? Because having anything EF related in business logic that you will need to unit test is a one way ticket to hell.
For my DbSets, I have a library that makes unit testing my interactions with them bearable, but even then it is not possible to verify the mock calls that get made due to the huge callstack that the library creates in memory. (It is not really "mocking" the interactions, but it takes away the burden of the huge setup that is required).
For the DatabaseFacade (which I need to call the BeginTransaction) there is a similar issue, namely that there is no interface wrapped around it which makes unit testing the above functionality very difficult. I could make a full in memory database based around a seperate DbContext to get the end result I need, problem is, that goes far beyond the scope of a unit test (and yes, it is a unit test - I am not trying to interact with the database, I am merely trying to see if the calls I want to make are invoked when I want them to be invoked). This might seem obvious, but as I looked around on the internet for possible solutions most of the responses boiled down to either 'You are not unit testing but integration testing' or 'Just make a repository interface to proxy the calls'. This second response doesn't solve the problem, because it forces the developer to proxy all the calls they want to make which is a lot of work. Work that could easily be handed off to (you guessed it) an interface. (There are already issues open about the DbContext not having an interface so I won't repeat that discussion here).

I would like to see the EF project use more interfaces in general, but since there is no request for a specific IDatabaseFacade interface here it is. I understand that it will not be included in the existing EF releases, but I hope my explanation has shown that it would be of great added value to the framework, and gets it on the roadmap for a future EF release (EF 7/8). And, if I have not yet convinced you for this feature, I am looking forward to the discussion that will ensue in this thread.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.