DEV Community

Jason Sultana
Jason Sultana

Posted on • Originally published at jason.sultana.net.au on

Writing unit tests for EF Core

G’day guys!

It’s been a while since I’ve had a good look at Entity Framework, since for the last couple of years I’ve been professionally living in mostly NoSQL-land. Earlier today though, I thought I’d crack open an old hobby project and add some unit tests for it. That’s easier said than done though unless you know what you’re doing, since DbContext by default is not easily unit testable.

Bro, do you even Moq?

I hear ya! It should be as simple as extracting an interface out of your context, mocking it with Moq and you’re done! The problem essentially is the DbSet<T> that you use to define your tables. Firstly, DbSet<T> is abstract, so it can’t be newed. On top of that, there are a whole plethora of methods on it that are a pain to mock - ToListAsync(), Where() chaining, IQueryable<T> logic, unions and other set operations and more. If I remember correctly, there was a Microsoft article published years ago which gave you an implementation for what was essentially a mockable DbSet<T>, but I’ve found a better solution: Moq.EntityFrameworkCore.

You can have a look at the official howto on Github, but the gist of it is:

        var mock = new Mock<IYourDbContext>();
        mock.Setup(m => m.Customers)
            .ReturnsDbSet(_customers); // This magic comes from Moq.EntityFrameworkCore

Enter fullscreen mode Exit fullscreen mode

And that’s it! Admittedly I haven’t tested it thoroughly, but for the simple-ish test cases that I have, it works like a dream. Looking at the source code interestingly looks quite similar to the Microsoft article, but even if it is just taking what Microsoft gave us and packaging it into a nice, easily-consumable chunk of nuget (I’m dreaming of Tim Tams), it’s much appreciated.

Anyway, that’s all from me - this might be my shortest post yet. Happy mocking!

Catch ya!

Oldest comments (3)

Collapse
 
dcarapic profile image
Dalibor Čarapić

I usually perform tests by switching to EF in-memory database during the tests. AFAIK this would ensure better testing as the behavior of the DbContext with in-memory database is more 'similar' to DbContext with your standard database.
Are there any benefits / drawbacks in using Moq vs EF in-memory database?

Collapse
 
fluffynuts profile image
Davyd McColl

Both will suffer from the edge-cases where in-memory works fine but the translation from your linq to server-side sql fails - I recommend using a temporary database with the same engine you're targeting. See my post above.

Collapse
 
fluffynuts profile image
Davyd McColl

I highly recommend not mocking your db store - the linq-to-sql conversions that have to happen can be specific to the underlying database - for instance, SQLCE only has an uppercase function, not a lowercase one, and you will find that you can extract methods from the bodies of your larger query methods which won't work server-side.

The whole point of a good unit test suite is to let you know when parts of your code don't do what you expect them to do. I used to mock my db contexts until I was bitten hard by something that compiles fine and works on in-memory collections perfectly, but didn't work at SQL Server.

It's a bit of a bigger hammer, but I recommend using one of the PeanutButter.TempDb libraries (disclaimer: I'm the author): nuget.org/packages?q=PeanutButter....

There is currently first-class support for SQL Server (via localdb), sqlite, sqlce and MySql (either via the opensource connector or via Oracle's). I'd love to add support for Firebird and Postgres, but haven't had a need to, yet; I have a feeling, from my prior use of Firebird, that it will be easy to support, but I'm not sure about Postgres. At any rate, if one of these supports an engine you're already using, I highly recommend it over mocked data contexts - one day you're going to come up against a test that works fine with code that fails horribly in production ):