I'm trying to unit test a few .NET classes that (for good design reasons) require DbConnections to do their work. For these tests, I have certain data in memory to give as input to these classes.
That in-memory data could be easily expressed as a DataTable (or a DataSet that contains that DataTable), but if another class were more appropriate I could use it.
If I were somehow magically able to get a DbConnection that represented a connection to the in-memory data, then I could construct my objects, have them execute their queries against the in-memory data, and ensure that their output matched expectations. Is there some way to get a DbConnection to in-memory data? I don't have the freedom to install any additional third-party software to make this happen, and ideally, I don't want to touch the disk during the tests.
Rather than consume a DbConnection can you consume IDbConnection and mock it? We do something similar, pass the mock a DataSet. DataSet.CreateDataReader returns a DataTableReader which inherits from DbDataReader.
We have wrapped DbConnection in our own IDbConnection-like interface to which we've added an ExecuteReader() method which returns a class that implements the same interfaces as DbDataReader. In our mock, ExecuteReader simply returns what DataSet.CreateDataReader serves up.
Sounds kind of roundabout, but it is very convenient to build up a DataSet with possibly many resultsets. We name the DataTables after the stored procs that they represent the results of, and our IDbConnection mock grabs the right Datatable based on the proc the client is calling. DataTable also implements CreateDataReader so we're good to go.
TypeMock? (You would need to 'install' it though).
Be careful assuming that Data* can give you proper hooks for testing - its pretty the worst case in general. But you say Good Design Reasons, so I'm sure that's all covered :D
An approach that I've used is to create an in-memory Sqlite database. This may be done simply by pulling in the System.Data.SQLite.Core NuGet package to your unit test project, you don't need to install any software anywhere else.
Although it sounds like a really obvious idea, it wasn't until I was looking at the Dapper unit tests that I thought to use the technique myself! See the "GetSqliteConnection" method in
https://github.com/StackExchange/dapper-dot-net/blob/bffb0972a076734145d92959dabbe48422d12922/Dapper.Tests/Tests.cs
One thing to be aware of is that if you create an in-memory sqlite db and create and populate tables, you need to be careful not to close the connection before performing your test queries because opening a new in-memory connection will get you a connection to a new in-memory database, not the database that you just carefully prepared for your tests! For some of my tests, I use a custom IDbConnection implementation that keeps the connection open to avoid this pitfall - eg.
https://github.com/ProductiveRage/SqlProxyAndReplay/blob/master/Tests/StaysOpenSqliteConnection.cs