Core Concepts
Challenges of NoSQL Testing
NoSQL database testing differs significantly from relational database testing:
- Document model complexity: MongoDB supports complex structures such as nested objects, arrays, and dictionaries
- No fixed schema: Data structure consistency needs to be verified through tests
- Diverse data structures: Redis has five main data structures, each with different use cases
- Serialization handling: BSON (MongoDB) and JSON (Redis) serialization behavior needs to be verified
Advantages of Testcontainers
- Real environment simulation: Uses actual MongoDB 7.0 and Redis 7.2 containers
- Consistency testing: Test results directly reflect production environment behavior
- Isolation guarantee: Each test environment is completely independent
- Performance verification: Enables real index performance testing
Environment Requirements
Required Packages
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<!-- MongoDB 相關套件 -->
<PackageReference Include="MongoDB.Driver" Version="3.7.1" />
<PackageReference Include="MongoDB.Bson" Version="3.7.1" />
<!-- Redis 相關套件 -->
<PackageReference Include="StackExchange.Redis" Version="2.12.8" />
<!-- Testcontainers -->
<PackageReference Include="Testcontainers" Version="4.11.0" />
<PackageReference Include="Testcontainers.MongoDb" Version="4.11.0" />
<PackageReference Include="Testcontainers.Redis" Version="4.11.0" />
<!-- 測試框架 -->
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5" />
<PackageReference Include="AwesomeAssertions" Version="9.4.0" />
<!-- JSON 序列化與時間測試 -->
<PackageReference Include="System.Text.Json" Version="10.0.5" />
<PackageReference Include="Microsoft.Bcl.TimeProvider" Version="10.0.5" />
<PackageReference Include="Microsoft.Extensions.TimeProvider.Testing" Version="10.4.0" />
</ItemGroup>
</Project>
Package Version Description
| Package | Version | Purpose |
|---|---|---|
| MongoDB.Driver | 3.7.1 | MongoDB official driver, supports the latest features |
| MongoDB.Bson | 3.7.1 | BSON serialization handling |
| StackExchange.Redis | 2.12.8 | Redis client, supports Redis 7.x |
| Testcontainers.MongoDb | 4.11.0 | MongoDB container management |
| Testcontainers.Redis | 4.11.0 | Redis container management |
MongoDB Containerized Testing
Covers MongoDB Container Fixture setup, complex document model design (nested objects, arrays, dictionaries), BSON serialization testing, CRUD operation testing (including optimistic locking), and index performance and uniqueness constraint testing. Uses the Collection Fixture pattern to share containers, saving more than 80% of testing time.
For complete code examples, refer to Detailed Guide to MongoDB Containerized Testing
Redis Containerized Testing
Covers Redis Container Fixture setup, cache model design (CacheItem generic wrapper, UserSession, RecentView, LeaderboardEntry), and complete test examples for Redis's five data structures (String, Hash, List, Set, Sorted Set), including TTL expiration testing and data isolation strategies.
For complete code examples, refer to Detailed Guide to Redis Containerized Testing
Best Practices
1. Collection Fixture Pattern
Use Collection Fixture to share containers and avoid restarting containers for each test:
// 定義集合
[CollectionDefinition("MongoDb Collection")]
public class MongoDbCollectionFixture : ICollectionFixture<MongoDbContainerFixture> { }
// 使用集合
[Collection("MongoDb Collection")]
public class MyMongoTests
{
public MyMongoTests(MongoDbContainerFixture fixture)
{
// 使用共享的容器
}
}
2. Data Isolation Strategy
Ensure tests do not interfere with each other:
// MongoDB:使用唯一的 Email/Username
var user = new UserDocument
{
Username = $"testuser_{Guid.NewGuid():N}",
Email = $"test_{Guid.NewGuid():N}@example.com"
};
// Redis:使用唯一的 Key 前綴
var testId = Guid.NewGuid().ToString("N")[..8];
var key = $"test:{testId}:mykey";
3. Cleanup Strategy
// MongoDB:測試後清理
await fixture.ClearDatabaseAsync();
// Redis:使用 KeyDelete 而非 FLUSHDB(避免權限問題)
var keys = server.Keys(database.Database);
if (keys.Any())
{
await database.KeyDeleteAsync(keys.ToArray());
}
4. Performance Considerations
| Strategy | Description |
|---|---|
| Collection Fixture | The container starts only once, saving 80%+ of time |
| Data isolation | Use unique Keys/IDs instead of clearing the database |
| Batch operations | Use InsertManyAsync, SetMultipleStringAsync |
| Index creation | Create indexes during Fixture initialization |
Frequently Asked Questions
Redis FLUSHDB Permission Issue
Some Redis container images do not enable admin mode by default:
// ❌ 錯誤:可能失敗
await server.FlushDatabaseAsync();
// ✅ 正確:使用 KeyDelete
var keys = server.Keys(database.Database);
if (keys.Any())
{
await database.KeyDeleteAsync(keys.ToArray());
}
MongoDB Unique Index Duplicate Insert
// 測試時使用唯一的 Email 避免衝突
var uniqueEmail = $"test_{Guid.NewGuid():N}@example.com";
Container Startup Timeout
// 增加等待時間
_container = new MongoDbBuilder()
.WithImage("mongo:7.0")
.WithWaitStrategy(Wait.ForUnixContainer()
.UntilCommandIsCompleted("mongosh --eval 'db.runCommand({ ping: 1 })'"))
.Build();
Related Skills
- testcontainers-database - PostgreSQL/MSSQL Containerized Testing
- aspnet-integration-testing - ASP.NET Core Integration Testing
- nsubstitute-mocking - Test Doubles and Mocks
- xunit-upgrade-guide - xUnit v3 Upgrade Guide (including Testcontainers.XunitV3 Integration)
Output Format
- Generate Container Fixture class (MongoDB/Redis container management)
- Generate test classes with Collection Fixture configuration
- Provide .csproj package reference configuration
- Include data isolation and container lifecycle management code
Reference Resources
Original Articles
The content of this skill is distilled from the "Old-School Software Engineer's Testing Practice - 30-Day Challenge" series of articles:
- Day 22 - Testcontainers Integration Testing: MongoDB and Redis from Basics to Advanced
- Ironman Series Article:https://ithelp.ithome.com.tw/articles/10376740
- Sample Code:https://github.com/kevintsengtw/30Days_in_Testing_Samples/tree/main/day22