Developer Testing Guide
Developer Testing Guide
This guide explains how to run and write tests for Morphium. It covers the test infrastructure, the MultiDriverTestBase class, and the runtests.sh script.
Quick Start
# Fast local testing with InMemoryDriver (no MongoDB needed)
./runtests.sh --driver inmem --restart
# Test against MorphiumServer (single node - recommended for most testing)
./runtests.sh --morphium-server --driver pooled --restart
# Test against MorphiumServer replica set (for replication testing)
./runtests.sh --morphium-server-replicaset --driver pooled --restart
# Run specific test class
./runtests.sh --driver inmem --test BasicFunctionalityTest
# Run with Maven directly
mvn test -Dmorphium.test.driver=inmem -Dtest=BasicFunctionalityTest
Test Infrastructure Overview
┌─────────────────────────────────────────────────────────────────┐
│ runtests.sh │
│ (orchestrates test runs, manages MorphiumServer, collects stats)│
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Maven Surefire Plugin │
│ (executes JUnit 5 tests with system properties) │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ MultiDriverTestBase │
│ (provides Morphium instances configured per driver type) │
└─────────────────────────────────────────────────────────────────┘
│
┌───────────────┼───────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────────┐
│InMemory │ │ Pooled │ │SingleConnect │
│ Driver │ │ Driver │ │ Driver │
└──────────┘ └──────────┘ └──────────────┘
│ │ │
▼ ▼ ▼
┌──────────┐ ┌─────────────────────────────┐
│In-Memory │ │ MongoDB / MorphiumServer │
│ Storage │ │ │
└──────────┘ └─────────────────────────────┘
MultiDriverTestBase
MultiDriverTestBase is the foundation for parameterized tests that run against multiple driver types.
How It Works
- Test classes extend
MultiDriverTestBaseand use JUnit 5@ParameterizedTestwith@MethodSource - Method sources like
getMorphiumInstances()returnStream<Arguments>with pre-configuredMorphiuminstances - Each test method receives a
Morphiuminstance as parameter and runs independently - Database isolation: Each driver instance gets a unique database name (
morphium_test_1,morphium_test_2, etc.)
Available Method Sources
| Method Source | Drivers Included |
|---|---|
getMorphiumInstances() | InMemory, Pooled |
getMorphiumInstancesNoSingle() | InMemory, Pooled |
getMorphiumInstancesPooledOnly() | Pooled only |
getMorphiumInstancesSingleOnly() | SingleConnect only |
getMorphiumInstancesInMemOnly() | InMemory only |
getMorphiumInstancesNoInMem() | Pooled, SingleConnect |
getInMemInstanceOnly() | InMemory only |
Writing a Test
import de.caluga.test.mongo.suite.base.MultiDriverTestBase;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
public class MyFeatureTest extends MultiDriverTestBase {
@ParameterizedTest
@MethodSource("getMorphiumInstances") // Runs with InMemory and Pooled
public void testMyFeature(Morphium morphium) throws Exception {
try (morphium) { // Auto-close when done
// Your test code here
UncachedObject obj = new UncachedObject("test", 1);
morphium.store(obj);
var result = morphium.createQueryFor(UncachedObject.class)
.f("counter").eq(1)
.get();
assertNotNull(result);
assertEquals("test", result.getStrValue());
}
}
}
Driver Selection via System Properties
The MultiDriverTestBase respects these system properties:
| Property | Values | Description |
|---|---|---|
morphium.driver | inmem, pooled, single, all | Which drivers to include |
morphium.database | e.g., morphium_test_slot1 | Base database name prefix |
morphium.tests.external | true/false | Enable external MongoDB tests |
When morphium.tests.external is not set (default), only InMemoryDriver is used regardless of morphium.driver setting. This allows fast local testing without MongoDB.
TestConfig
TestConfig.java centralizes test configuration with this precedence:
- System properties (
-Dmorphium.xxx) - Environment variables (
MORPHIUM_XXX) morphium-test.propertiesresource file- Built-in defaults
Key configuration options:
# Connection
morphium.uri=mongodb://localhost:27017/test
morphium.hostSeed=localhost:27017,localhost:27018
morphium.database=morphium_test
# Driver
morphium.driver=pooled # pooled|single|inmem
# Authentication
morphium.user=testuser
morphium.pass=testpass
morphium.authDb=admin
# Timeouts (milliseconds)
morphium.connectionTimeout=2000
morphium.readTimeout=10000
morphium.serverSelectionTimeout=15000
runtests.sh Script
The runtests.sh script provides a convenient wrapper around Maven with additional features.
Command Line Options
Driver Selection
--driver NAME # pooled|single|inmem (default: inmem if no external)
--external # Enable external MongoDB tests
Test Selection
--test PATTERN # Run only matching test classes
--tags LIST # Include JUnit 5 tags (comma-separated)
--exclude-tags LIST # Exclude JUnit 5 tags
--rerunfailed # Rerun only previously failed tests
Available tags: core, messaging, driver, inmemory, aggregation, cache, admin, performance, encryption, jms, geo, util, external
MorphiumServer Options
--morphium-server # Start single-node MorphiumServer (recommended)
--morphium-server-replicaset # Start 3-node replica set (ports 27017-27019)
Execution Control
--parallel N # Run tests in N parallel slots (1-16)
--retry N # Retry failed tests N times
--restart # Clear logs and start fresh
--skip # Skip already-run tests (continue mode)
Output Control
--logs NUM # Number of log lines to show
--refresh NUM # Refresh display every NUM seconds
--stats # Show test statistics
--verbose # Enable verbose test output
Examples
# Fast development cycle - InMemory only
./runtests.sh --driver inmem --test MyNewTest --restart
# Full test against MorphiumServer single node
./runtests.sh --morphium-server --driver pooled --restart
# Parallel testing for speed
./runtests.sh --driver inmem --parallel 4 --restart
# Test specific tags
./runtests.sh --driver inmem --tags core,messaging --restart
# Rerun failed tests with retries
./runtests.sh --rerunfailed --retry 3
# External MongoDB with authentication
./runtests.sh --external --driver pooled \
--uri mongodb://user:pass@mongo1:27017/test?authSource=admin
Log Files
- Sequential runs:
test.log/<TestClass>.log - Parallel runs:
test.log/slot_<N>/<TestClass>.log - MorphiumServer logs:
.morphiumserver-local/logs/morphiumserver_<port>.log - Failed tests summary:
failed.txt
Best Practices
1. Use InMemoryDriver for Development
./runtests.sh --driver inmem --test YourTest
- No external dependencies
- Fast execution
- Full feature parity for most operations
2. Use try-with-resources
@ParameterizedTest
@MethodSource("getMorphiumInstances")
public void myTest(Morphium morphium) throws Exception {
try (morphium) { // Ensures cleanup
// test code
}
}
3. Wait for Async Operations
// Use TestUtils for waiting
TestUtils.waitForConditionToBecomeTrue(5000, "Data not stored",
() -> morphium.createQueryFor(MyClass.class).countAll() == expectedCount);
4. Handle Replica Set Timing
When testing against replica sets (MorphiumServer or MongoDB), data replication takes time:
// Allow time for replication (increase timeout for replica sets)
TestUtils.waitForConditionToBecomeTrue(5000, "Replication timeout",
() -> query.countAll() == expected);
5. Clean Test Data
MultiDriverTestBase automatically drops test databases before each test run. For additional cleanup within tests:
morphium.dropCollection(MyClass.class);
6. Tag Your Tests Appropriately
@Tag("core") // Core functionality
@Tag("messaging") // Messaging tests
@Tag("performance") // Slow performance tests
@Tag("external") // Requires external MongoDB
@Tag("inmemory") // InMemory-specific tests
7. Use Appropriate Method Sources
// For tests that work with any driver
@MethodSource("getMorphiumInstances")
// For tests requiring real MongoDB features
@MethodSource("getMorphiumInstancesNoInMem")
// For InMemory-specific behavior tests
@MethodSource("getMorphiumInstancesInMemOnly")
Troubleshooting
Test Hangs
- Check for infinite loops in wait conditions
- Verify MorphiumServer is running (if using
--morphium-server) - Check connection timeouts in logs
Flaky Tests with Replica Sets
Replica set tests can be timing-sensitive:
- Increase wait timeouts for replication
- Use
--morphium-server(single node) instead of--morphium-server-replicasetfor most tests - Run flaky tests with
--retry 2
Database Conflicts in Parallel Mode
Each parallel slot uses a unique database prefix. If you see conflicts:
- Ensure tests use
morphiumparameter, not shared static instances - Check that
--restartis used to clear old data - Verify tests close their Morphium instances properly
View Test Statistics
./runtests.sh --stats # Full statistics
./runtests.sh --stats --noreason # Just test names
cat failed.txt # List of failed tests
Running with Maven Directly
For IDE integration or CI pipelines:
# InMemory (default, no external MongoDB needed)
mvn test -Dmorphium.test.driver=inmem
# External MongoDB
mvn test -Pexternal -Dmorphium.driver=pooled \
-Dmorphium.uri=mongodb://localhost:27017/test
# Specific test
mvn test -Dtest=BasicFunctionalityTest -Dmorphium.test.driver=inmem
# With tags
mvn test -Dgroups=core,messaging -DexcludedGroups=performance
See Also
- Test Runner Reference - Additional
runtests.shdetails - InMemory Driver - InMemoryDriver specifics
- MorphiumServer - MorphiumServer documentation