Skip to content

Unit Testing

Aryeh Citron edited this page May 12, 2026 · 3 revisions

Unit Testing

Basic Setup

using InMemoryEmulator.MongoDB;
using MongoDB.Driver;

public class OrderServiceTests
{
    private readonly IMongoCollection<Order> _collection;

    public OrderServiceTests()
    {
        var result = InMemoryMongo.Create<Order>("orders");
        _collection = result.Collection;
    }

    [Fact]
    public async Task Can_create_and_find_order()
    {
        await _collection.InsertOneAsync(new Order { CustomerId = "c1", Total = 100 });

        var found = await _collection
            .Find(o => o.CustomerId == "c1")
            .FirstOrDefaultAsync();

        Assert.NotNull(found);
        Assert.Equal(100, found.Total);
    }
}

CRUD Operations

Insert

await collection.InsertOneAsync(new Order { Total = 50 });
await collection.InsertManyAsync(orders);

Find

// Filter builder
var filter = Builders<Order>.Filter.Gt(o => o.Total, 100);
var results = await collection.Find(filter).ToListAsync();

// LINQ
var results = collection.AsQueryable().Where(o => o.Total > 100).ToList();

// Count
var count = await collection.CountDocumentsAsync(filter);

Update

var filter = Builders<Order>.Filter.Eq(o => o.Id, orderId);
var update = Builders<Order>.Update.Set(o => o.Status, "shipped");
await collection.UpdateOneAsync(filter, update);

Replace

var replacement = new Order { Id = orderId, Status = "completed", Total = 200 };
await collection.ReplaceOneAsync(o => o.Id == orderId, replacement);

Delete

await collection.DeleteOneAsync(o => o.Id == orderId);
await collection.DeleteManyAsync(o => o.Status == "cancelled");

Filter & Update Builders

All standard MongoDB filter and update builder operations are supported. Examples:

// Comparison operators
var filter = Builders<Order>.Filter.Gte("total", 100) &
             Builders<Order>.Filter.Lt("total", 500);

// Array operators
var filter = Builders<Order>.Filter.AnyIn("tags", new[] { "urgent", "priority" });

// Update with multiple operators
var update = Builders<Order>.Update
    .Set("status", "processing")
    .Inc("version", 1)
    .CurrentDate("updatedAt");

See Filter & Update Operators for the complete list.

Aggregation Pipeline

var results = await collection.Aggregate()
    .Match(o => o.Status == "completed")
    .Group(o => o.CustomerId, g => new
    {
        CustomerId = g.Key,
        TotalSpent = g.Sum(o => o.Total),
        OrderCount = g.Count()
    })
    .SortByDescending(g => g.TotalSpent)
    .Limit(10)
    .ToListAsync();

See Aggregation Pipeline for all 34 supported stages.

Test Isolation

Each InMemoryMongo.Create<T>() call or DI registration creates an independent in-memory store. Tests are naturally isolated — no shared state, no cleanup needed.

Per-test isolation with xUnit

public class OrderTests : IAsyncLifetime
{
    private IMongoCollection<Order> _collection = null!;

    public ValueTask InitializeAsync()
    {
        _collection = InMemoryMongo.Create<Order>("orders").Collection;
        return ValueTask.CompletedTask;
    }

    public ValueTask DisposeAsync() => ValueTask.CompletedTask;
}

Shared fixture with explicit reset

// If sharing a collection across tests, clear between tests:
var db = result.Database as InMemoryMongoDatabase;
db?.ClearDocuments();

See Also

Clone this wiki locally