Repository navigation
Unit Testing
For unit tests that don''t use dependency injection, create an InMemoryContainer directly and pass it to the code under test. Since InMemoryContainer extends the SDK''s abstract Container class, any code that depends on Container works without changes.
using CosmosDB.InMemoryEmulator;
using Microsoft.Azure.Cosmos;
var container = new InMemoryContainer("my-container", "/partitionKey");The two required arguments are the container name and partition key path. The container is ready to use immediately — no database or client needed.
[Fact]
public async Task CreateAndRead_RoundTrips()
{
var container = new InMemoryContainer("orders", "/customerId");
// Create
var order = new { id = "1", customerId = "cust-1", product = "Widget", price = 9.99 };
var createResponse = await container.CreateItemAsync(order, new PartitionKey("cust-1"));
Assert.Equal(HttpStatusCode.Created, createResponse.StatusCode);
// Read
var readResponse = await container.ReadItemAsync<dynamic>("1", new PartitionKey("cust-1"));
Assert.Equal("Widget", (string)readResponse.Resource.product);
// Upsert
var updated = new { id = "1", customerId = "cust-1", product = "Widget", price = 12.99 };
await container.UpsertItemAsync(updated, new PartitionKey("cust-1"));
// Delete
await container.DeleteItemAsync<dynamic>("1", new PartitionKey("cust-1"));
}[Fact]
public async Task Query_FiltersCorrectly()
{
var container = new InMemoryContainer("products", "/category");
await container.CreateItemAsync(
new { id = "1", category = "electronics", name = "Laptop", price = 999 },
new PartitionKey("electronics"));
await container.CreateItemAsync(
new { id = "2", category = "electronics", name = "Mouse", price = 25 },
new PartitionKey("electronics"));
await container.CreateItemAsync(
new { id = "3", category = "books", name = "C# in Depth", price = 40 },
new PartitionKey("books"));
var query = new QueryDefinition("SELECT * FROM c WHERE c.price > @min")
.WithParameter("@min", 30);
var iterator = container.GetItemQueryIterator<dynamic>(query);
var results = new List<dynamic>();
while (iterator.HasMoreResults)
{
var page = await iterator.ReadNextAsync();
results.AddRange(page);
}
Assert.Equal(2, results.Count);
}See SQL Queries for the full reference — 100+ built-in functions, JOINs, GROUP BY, aggregates, and more.
InMemoryContainer supports GetItemLinqQueryable<T>() which returns a LINQ-to-Objects queryable:
[Fact]
public async Task Linq_FiltersAndProjects()
{
var container = new InMemoryContainer("orders", "/customerId");
await container.CreateItemAsync(
new Order { Id = "1", CustomerId = "cust-1", Product = "Widget", Price = 9.99m },
new PartitionKey("cust-1"));
await container.CreateItemAsync(
new Order { Id = "2", CustomerId = "cust-1", Product = "Gadget", Price = 49.99m },
new PartitionKey("cust-1"));
var expensive = container.GetItemLinqQueryable<Order>(true)
.Where(o => o.Price > 20)
.ToList();
Assert.Single(expensive);
Assert.Equal("Gadget", expensive[0].Product);
}Note: LINQ queries here execute as LINQ-to-Objects (C# delegates against in-memory data). They don''t go through the Cosmos SQL translation. If you need to test the SDK''s LINQ-to-SQL translation, use the FakeCosmosHandler approach.
The most common pattern — your repository depends on Container, and you pass in an InMemoryContainer:
// Production code (unchanged)
public class OrderRepository
{
private readonly Container _container;
public OrderRepository(Container container) => _container = container;
public async Task<Order> CreateAsync(Order order)
{
var response = await _container.CreateItemAsync(order, new PartitionKey(order.CustomerId));
return response.Resource;
}
public async Task<List<Order>> GetByCustomerAsync(string customerId)
{
var query = new QueryDefinition("SELECT * FROM c WHERE c.customerId = @id")
.WithParameter("@id", customerId);
var iterator = _container.GetItemQueryIterator<Order>(query);
var results = new List<Order>();
while (iterator.HasMoreResults)
{
var page = await iterator.ReadNextAsync();
results.AddRange(page);
}
return results;
}
}
// Test
public class OrderRepositoryTests
{
[Fact]
public async Task GetByCustomer_ReturnsOnlyMatchingOrders()
{
var container = new InMemoryContainer("orders", "/customerId");
var repo = new OrderRepository(container);
await repo.CreateAsync(new Order { Id = "1", CustomerId = "cust-1", Product = "Widget" });
await repo.CreateAsync(new Order { Id = "2", CustomerId = "cust-2", Product = "Gadget" });
await repo.CreateAsync(new Order { Id = "3", CustomerId = "cust-1", Product = "Sprocket" });
var results = await repo.GetByCustomerAsync("cust-1");
Assert.Equal(2, results.Count);
Assert.All(results, o => Assert.Equal("cust-1", o.CustomerId));
}
}[Fact]
public async Task Patch_UpdatesSingleProperty()
{
var container = new InMemoryContainer("orders", "/customerId");
await container.CreateItemAsync(
new { id = "1", customerId = "cust-1", status = "pending" },
new PartitionKey("cust-1"));
await container.PatchItemAsync<dynamic>("1", new PartitionKey("cust-1"),
new[] { PatchOperation.Set("/status", "shipped") });
var response = await container.ReadItemAsync<dynamic>("1", new PartitionKey("cust-1"));
Assert.Equal("shipped", (string)response.Resource.status);
}Configure TTL, unique keys, and other container-level settings:
var container = new InMemoryContainer("orders", "/customerId",
new InMemoryContainerOptions
{
DefaultTimeToLive = TimeSpan.FromHours(1)
});See API Reference for all available options.
If your system under test uses dependency injection, consider the DI approach instead — it requires zero setup in individual tests and automatically replaces all Cosmos registrations.
For maximum SDK fidelity (testing the full HTTP pipeline, LINQ-to-SQL translation, fault injection), see FakeCosmosHandler.
Getting Started
Integration & Dependency Injection
Data Management
Reference
Help