Installation: Require the package via Composer:
composer require mpyw/laravel-database-mock:dev-main
(Note: Use dev-main for the latest alpha, as per the README.)
First Mock: Start by mocking a PDO connection in your test setup:
use Mpyw\LaravelDatabaseMock\Facades\DBMock;
public function setUp(): void
{
parent::setUp();
$this->pdo = DBMock::mockPdo(); // Mocks the default connection
}
Basic Query Mocking: Define expectations for a SELECT query in a test:
$this->pdo->shouldSelect('select * from users')
->shouldFetchAllReturns([['id' => 1, 'name' => 'Test User']]);
Verify Behavior: Assert the mocked response in your test:
$this->assertEquals([['id' => 1, 'name' => 'Test User']], User::all()->toArray());
Mpyw\LaravelDatabaseMock\Facades\DBMock (primary entry point).SELECT/INSERT examples cover 80% of daily use cases.Setup Phase:
public function setUp(): void
{
$this->pdo = DBMock::mockPdo(); // Mock default connection
$this->pdo->shouldSelect('select * from products')->shouldFetchAllReturns([...]);
$this->pdo->shouldInsert('insert into orders (...)')->shouldReturn(1); // Simulate auto-increment
}
Dynamic Mocking: Useful for conditional logic or parameterized queries:
$this->pdo->shouldReceive('prepare->execute')
->once()
->with('select * from users where id = ?', [1])
->andReturnUsing(function () {
return $this->pdo->shouldFetchAllReturns([...]);
});
Connection-Specific Mocks:
Target a specific database connection (e.g., mysql, sqlite):
DBMock::mockPdo('mysql'); // Explicit connection name
Transaction Mocking: Simulate transactions by chaining expectations:
$this->pdo->shouldBeginTransaction()
->shouldInsert('...')->shouldReturn(1)
->shouldCommit();
Query Builder Integration: Mock Eloquent queries indirectly via raw PDO:
$this->pdo->shouldSelect('select * from posts where user_id = ?')
->with([1])
->shouldFetchAllReturns([...]);
Time Travel: Combine with Carbon’s test time for consistent timestamps:
Carbon::setTestNow('2023-01-01');
$this->pdo->shouldInsert('... created_at, updated_at ...')->shouldReturn(1);
DatabaseMigrations or DatabaseTransactions for partial mocking.DB facade binding in tests if needed:
$this->app->bind('db.connection', function () {
return DBMock::mockPdo()->getConnection();
});
$this->pdo->shouldHaveReceived('query')->once();
Connection Leaks:
DBMock::reset() or Mockery’s Mockery::close() in tearDown():
public function tearDown(): void {
DBMock::reset();
parent::tearDown();
}
Case Sensitivity:
SELECT vs select).$this->pdo->shouldReceive('query')->with('/select.*from users/i');
Parameter Binding:
?) may not match Laravel’s query builder bindings (:id).$this->pdo->shouldSelect('select * from users where id = :id')
->with(['id' => 1])
->shouldFetchAllReturns([...]);
Auto-Increment IDs:
INSERT queries may not auto-increment IDs by default.$this->pdo->shouldInsert('...')->shouldReturn(1);
$this->pdo->shouldReceive('lastInsertId')->andReturn(1);
Transaction Rollbacks:
rollBack():
$this->pdo->shouldRollBack();
Enable Mockery Logging:
Add this to phpunit.xml to debug unexpected calls:
<php>
<server name="MOCKERY_LOG" value="1"/>
</php>
Inspect Mocked Calls: Dump the mock’s interactions:
var_dump($this->pdo->getMock()->getInvocations());
Partial Mocks:
Use allowMockeryIsolation() to mock only specific methods:
$pdo = DBMock::mockPdo()->allowMockeryIsolation();
$pdo->shouldReceive('query')->andReturn(...);
Custom Mock Classes:
Extend Mpyw\MockeryPdo\MockPDO to add domain-specific methods:
class CustomMockPDO extends MockPDO {
public function shouldFetchUser($id) {
return $this->shouldSelect("select * from users where id = ?")
->with([$id])
->shouldFetchAllReturns([...]);
}
}
Then bind it in your test setup.
Global Mocking:
Override the DBMock facade to apply defaults:
DBMock::macro('mockPdo', function () {
$pdo = parent::mockPdo();
$pdo->shouldReceive('setAttribute')->with(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
return $pdo;
});
Query Logging: Log all mocked queries for debugging:
$this->pdo->shouldReceive('*')->andReturnUsing(function ($method, $args) {
\Log::debug("Mocked: {$method} with " . json_encode($args));
// ... rest of the logic
});
Performance: For heavy test suites, cache mock configurations:
static private $mockCache = [];
if (!isset(self::$mockCache['users'])) {
self::$mockCache['users'] = DBMock::mockPdo()->shouldSelect('...')->shouldFetchAllReturns([...]);
}
$this->pdo = self::$mockCache['users'];
How can I help you explore Laravel packages today?