Unit test an event handler that uses Entity Framework

sql-persistence
nservicebus

(Barry Schulz) #1

What is the best way to unit test the code from the sample below?

I am using the TestableMessageHandlerContext, but there does not seem to be a way to mock the SynchronizedStorageSession because StorageSession is an internal class and SqlPersistenceSession is an extension method.

I am also using the in memory database supplied by EF.

A) Should I be passing in the DbContext via the handler’s constructor
B) Do something similar to what is done here https://docs.particular.net/samples/entity-framework/
C) Other

https://docs.particular.net/samples/sqltransport-sqlpersistence/
var session = context.SynchronizedStorageSession.SqlPersistenceSession();

var order = new SubmittedOrder
{
    Id = $"EF-{message.OrderId}",
    Value = message.Value,
};

using (var dbContext = new SubmittedOrderDbContext(session.Connection))
{
    dbContext.Database.UseTransaction(session.Transaction);
    await dbContext.SubmittedOrder.AddAsync(order)
        .ConfigureAwait(false);
    await dbContext.SaveChangesAsync()
        .ConfigureAwait(false);
}

(Ramon Smits) #2

I would manage the DbContext via a behavior and not in the handler. The handler should have a way to get the reference to the DbContext.

The handler get retrieve the DbContext via a helper that is injected via the constructor. This helper is than used in the Handle method to get the context.

I handled a similar question recently and I have a project that contains a workable solution:

The easiest approach is to wrap the static extension method (SynchronizedStorageSession()) to a sort of provider that is injected into the handler. This way you can easily test a handler and fake/mock dependencies to your liking:

As can be seen in the test, that wrapper is easiliy mocked to return a testable dbcontext.

You may notice that the handler itself isn’t managing the lifetime of the DbContext, this is done via a behavior:

The linked solution was a reproduction for another issue to isn’t focused on this specific problem but let me know if this helps you come up with a working solution or if I need to simplify it.

– Ramon