Simple.Data

Simple.Data has always been designed with "testing as a core feature" and supports unit testing your whole application stack using the InMemoryAdapter found in the Core namespace. The InMemoryAdapter supports all the actions and methods that all the other adapters does; including joins, transactions and stored procedures.

Testing : Advanced Scenarios

The examples above is very simplified, but have no fear; the InMemoryAdapter supports all the actions and methods that all the other adapters does; including joins, transactions and even stored procedures. Here are a few examples:

Update

// Configure adapter and insert a record
Database.UseMockAdapter(new InMemoryAdapter());
var db = Database.Open();
db.Test.Insert(Id: 1, Name: "Alice");

// Update record and get number of updated rows
int updated = db.Test.UpdateById(Id: 1, Name: "Allyce");
Assert.AreEqual(1, updated);

// Find and assert the updated record
var record = db.Test.FindById(1);
Assert.AreEqual("Allyce", record.Name);

DeleteBy

// Configure adapter and insert a record
Database.UseMockAdapter(new InMemoryAdapter());
var db = Database.Open();
db.Test.Insert(Id: 1, Name: "Alice");

// Delete by Id and get the number of deleted records
int deleted = db.Test.DeleteById(1);
Assert.AreEqual(1, deleted);

// Try to find the record and assert that it's gone!
var record = db.Test.FindById(1);
Assert.IsNull(record);

OrderBy

// Configure adapter and insert 10 records
Database.UseMockAdapter(new InMemoryAdapter());
var db = Database.Open();
for (int i = 0; i < 10; i++)
{
    db.Test.Insert(Id: i, Name: "Alice");
}

// Return records OrderBy Id Descending
var records = db.Test.All().OrderByIdDescending().ToList();

// Assert that the first record has Id 9
Assert.AreEqual(9, records[0].Id);

Join

// Configure the adapter with the Master/Detail-relation
// Make sure the naming in the strings here are aligned with the naming used in your code
var adapter = new InMemoryAdapter();
adapter.Join.Master("Customer", "ID").Detail("Order", "CustomerID");
Database.UseMockAdapter(adapter);

// Insert data in the 2 tables
var db = Database.Open();
db.Customer.Insert(ID: 1, Name: "NASA");
db.Customer.Insert(ID: 2, Name: "ACME");
db.Order.Insert(ID: 1, CustomerID: 1, Date: new DateTime(1997, 1, 12));
db.Order.Insert(ID: 2, CustomerID: 2, Date: new DateTime(2001, 1, 1));

// Retrieve the data and use the relation (db.Customer.Order)
var customers = db.Customer.FindAll(db.Customer.Order.Date < new DateTime(1999, 12, 31)).ToList();
Assert.IsNotNull(customers);
Assert.AreEqual(1, customers.Count);

Stored procedure

The InMemoryAdapter supports calling into stored procedures. You have to supply a delegate that returns what's expected but that can easily be faked for tests.

In this example we are testing a stored procedure called "Test" with 2 parameters. And the delegate we supply simply returns a Dictionary<string, object> with the values sent to the function. Why a Dictionary<string, object>? Well that's how the rows are stored within the InMemoryAdapter.

var adapter = new InMemoryAdapter();

// Set up the stored procedure
adapter.AddFunction<string, object, 
    IDictionary<string, object>>("Test", (key, value) => 
        new Dictionary<string, object> { { key, value } });

Database.UseMockAdapter(adapter);
var db = Database.Open();

// Call the Test stored procedure (db.Test) and assert the result
foreach (var row in db.Test("Foo", "Bar"))
{
    Assert.AreEqual("Bar", row.Foo);
}

Transactions

// Configure adapater
var adapter = new InMemoryAdapter();
Database.UseMockAdapter(adapter);
var db = Database.Open();

// Insert under transaction and make sure it's returned
using (var tx = db.BeginTransaction())
{
    tx.Test.Insert(Id: 1, Name: "Alice");
    var record = tx.Test.FindById(1);
    Assert.IsNotNull(record);
    Assert.AreEqual(1, record.Id);
    Assert.AreEqual("Alice", record.Name);
}