Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Database Mock Laravel Package

mpyw/laravel-database-mock

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. 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.)

  2. 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
    }
    
  3. Basic Query Mocking: Define expectations for a SELECT query in a test:

    $this->pdo->shouldSelect('select * from users')
        ->shouldFetchAllReturns([['id' => 1, 'name' => 'Test User']]);
    
  4. Verify Behavior: Assert the mocked response in your test:

    $this->assertEquals([['id' => 1, 'name' => 'Test User']], User::all()->toArray());
    

Where to Look First

  • Facade: Mpyw\LaravelDatabaseMock\Facades\DBMock (primary entry point).
  • Mockery-PDO Docs: Understand the mockery-pdo library, as this package builds on it.
  • Test Examples: The README’s SELECT/INSERT examples cover 80% of daily use cases.

Implementation Patterns

Workflow: Mocking a Full Test Suite

  1. 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
    }
    
  2. 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([...]);
        });
    
  3. Connection-Specific Mocks: Target a specific database connection (e.g., mysql, sqlite):

    DBMock::mockPdo('mysql'); // Explicit connection name
    
  4. Transaction Mocking: Simulate transactions by chaining expectations:

    $this->pdo->shouldBeginTransaction()
        ->shouldInsert('...')->shouldReturn(1)
        ->shouldCommit();
    
  5. Query Builder Integration: Mock Eloquent queries indirectly via raw PDO:

    $this->pdo->shouldSelect('select * from posts where user_id = ?')
        ->with([1])
        ->shouldFetchAllReturns([...]);
    
  6. 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);
    

Integration Tips

  • Hybrid Testing: Use alongside Laravel’s built-in DatabaseMigrations or DatabaseTransactions for partial mocking.
  • Service Provider Binding: Override the DB facade binding in tests if needed:
    $this->app->bind('db.connection', function () {
        return DBMock::mockPdo()->getConnection();
    });
    
  • Mockery Assertions: Leverage Mockery’s verification methods:
    $this->pdo->shouldHaveReceived('query')->once();
    

Gotchas and Tips

Pitfalls

  1. Connection Leaks:

    • Issue: Forgetting to reset mocks between tests can cause flaky tests.
    • Fix: Use DBMock::reset() or Mockery’s Mockery::close() in tearDown():
      public function tearDown(): void {
          DBMock::reset();
          parent::tearDown();
      }
      
  2. Case Sensitivity:

    • Issue: SQL queries are case-sensitive in mocks (e.g., SELECT vs select).
    • Fix: Normalize queries in tests or use regex:
      $this->pdo->shouldReceive('query')->with('/select.*from users/i');
      
  3. Parameter Binding:

    • Issue: Mockery-PDO’s parameter binding (?) may not match Laravel’s query builder bindings (:id).
    • Fix: Use raw PDO queries or mock the query builder directly:
      $this->pdo->shouldSelect('select * from users where id = :id')
          ->with(['id' => 1])
          ->shouldFetchAllReturns([...]);
      
  4. Auto-Increment IDs:

    • Issue: Mocked INSERT queries may not auto-increment IDs by default.
    • Fix: Manually set the last insert ID:
      $this->pdo->shouldInsert('...')->shouldReturn(1);
      $this->pdo->shouldReceive('lastInsertId')->andReturn(1);
      
  5. Transaction Rollbacks:

    • Issue: Mocked transactions may not roll back automatically.
    • Fix: Explicitly mock rollBack():
      $this->pdo->shouldRollBack();
      

Debugging Tips

  1. Enable Mockery Logging: Add this to phpunit.xml to debug unexpected calls:

    <php>
        <server name="MOCKERY_LOG" value="1"/>
    </php>
    
  2. Inspect Mocked Calls: Dump the mock’s interactions:

    var_dump($this->pdo->getMock()->getInvocations());
    
  3. Partial Mocks: Use allowMockeryIsolation() to mock only specific methods:

    $pdo = DBMock::mockPdo()->allowMockeryIsolation();
    $pdo->shouldReceive('query')->andReturn(...);
    

Extension Points

  1. 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.

  2. 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;
    });
    
  3. 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
    });
    
  4. 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'];
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
daikazu/eloquent-salesforce-objects
unseen-codes/chat
romalytar/yammi-jobs-monitoring-laravel
kisame76/filament-db-table-state
nqxcode/laravel-lucene-search
dpfx/laravel-livewire-wizards
workos/workos-php-laravel
sofa/laravel-global-scope
nawasara/auth-primitives
adhocrat-io/arkhe-main
make-dev/orca-harpoon
itsemon245/lamet
baks-dev/dashboard
amoifr/pickle-panther-bundle
make-dev/orca
dmstr/symfony-system-resources-bundle
dmstr/symfony-job-queue-bundle
dmstr/openapi-json-schema-bundle
dmstr/keycloak-security-bundle
dmstr/doctrine-audit-log-bundle