Installation:
composer require --dev helmich/mongomock
Ensure your composer.json declares a compatible PHPUnit version (6.x–9.x).
Basic Usage:
Replace real MongoDB\Collection/MongoDB\Database instances with MockCollection/MockDatabase in your test classes:
use Helmich\MongoMock\MockCollection;
$collection = new MockCollection();
$collection->insertOne(['name' => 'Test']);
First Test Case: Verify CRUD operations without a real MongoDB connection:
$collection = new MockCollection();
$id = $collection->insertOne(['foo' => 'bar'])->insertedId();
$result = $collection->findOne(['_id' => $id]);
$this->assertEquals('bar', $result['foo']);
MockCollection: Core class for in-memory document storage and querying.MockDatabase: Wraps MockCollection for database-level operations (e.g., listCollections()).assertDocumentCount() for fluent assertions.Test Isolation:
Use MockCollection to reset state between tests:
public function testUserCreation()
{
$collection = new MockCollection();
$collection->insertOne(['name' => 'Alice']);
$this->assertEquals(1, $collection->countDocuments([]));
}
public function testUserDeletion()
{
$collection = new MockCollection(); // Fresh instance
$collection->insertOne(['name' => 'Bob']);
$collection->deleteOne(['name' => 'Bob']);
$this->assertEquals(0, $collection->countDocuments([]));
}
Complex Queries: Leverage extended filter syntax (callbacks/constraints):
$collection->insertMany([
['age' => 25],
['age' => 30],
]);
$result = $collection->find(['age' => function($age) {
return $age > 25;
}]);
$this->assertCount(1, $result);
Update Operations:
Test atomic modifiers ($set, $inc, etc.):
$collection->insertOne(['count' => 5]);
$collection->updateOne([], ['$inc' => ['count' => 2]]);
$this->assertEquals(7, $collection->findOne([])['count']);
Aggregation Pipelines: Mock aggregation stages (limited support; verify against real MongoDB):
$result = $collection->aggregate([['$match' => ['foo' => 'bar']]]);
Dependency Injection:
Use Laravel’s MockCollection binding in config/services.php:
'mongo' => [
'mock' => true,
],
Then resolve via app(MockCollection::class).
Test Doubles:
Replace MongoDB\Client with a custom factory:
$client = Mockery::mock(MongoDB\Client::class);
$client->shouldReceive('selectDatabase')
->andReturn(new MockDatabase(['test' => new MockCollection()]));
BSON Handling:
Use MongoDB\BSON\* classes for type safety in tests:
$collection->insertOne(['timestamp' => new MongoDB\BSON\UTCDateTime()]);
API Limitations:
bulkWrite()). Check the source for gaps.BSON Quirks:
ObjectId vs. string).$regex operator explicitly for pattern matching:
$collection->find(['name' => ['$regex' => '/^A/']]);
State Management:
MockCollection instances across unrelated tests to prevent state leakage.PHPUnit Constraints:
PHPUnit\Framework\Constraint\* (not PHPUnit_Framework_Constraint) for PHPUnit 9+:
use PHPUnit\Framework\Constraint\IsInstanceOf;
$collection->find(['data' => new IsInstanceOf(MongoDB\BSON\Binary::class)]);
Query Validation: Log queries to verify syntax:
$collection->insertOne(['query' => ['$where' => 'this.foo > 10']]);
// Check raw query structure via reflection if needed.
Performance:
Large datasets may slow tests. Use countDocuments() instead of find() for assertions:
$this->assertEquals(100, $collection->countDocuments([]));
Custom Operators:
Extend MockCollection to support missing operators (e.g., $lookup):
class ExtendedMockCollection extends MockCollection {
public function aggregate(array $pipeline) {
// Implement custom logic
}
}
Database-Level Mocks:
Override MockDatabase methods like drop() or command() for edge cases:
$db = new class extends MockDatabase {
public function drop() {
// Custom drop logic
}
};
Assertion Helpers:
Add custom assertions to phpunit.xml:
<extensions>
<extension class="Helmich\MongoMock\PHPUnit\Assertions"/>
</extensions>
PHPUnit Version:
Ensure composer.json constraints align with your PHPUnit version (e.g., ^9.0 for PHPUnit 9).
"require-dev": {
"phpunit/phpunit": "^9.0"
}
Laravel Integration:
Use Mockery for seamless mocking in Laravel’s service container:
$this->mock(MongoDB\Client::class, function($mock) {
$mock->shouldReceive('selectDatabase')
->andReturn(new MockDatabase(['test' => new MockCollection()]));
});
How can I help you explore Laravel packages today?