skip to Main Content

In many frameworks like Springboot, mocking the database is common practice because it’s an external resource and it can increase latency with testing.

I haven’t seen that so far from Laravel. Is there an offering or documentation around mocking the database calls?

We have tried using some smaller libraries but they are volatile to change and we need an enterprise solution.

2

Answers


  1. Yes, Laravel provides robust capabilities for testing.

    If you’re using PHPUnit, in phpunit.xml

    <server name="DB_CONNECTION" value="sqlite"/>
    <server name="DB_DATABASE" value=":memory:"/>
    

    Or with RefreshDatabase, read Quick tip: How to set up in-memory database for Laravel unit tests


    As well we have Mocking Facades, Mocking

    DB::shouldReceive('table')
        ->once()
        ->with('products')
        ->andReturn(new class {
            public function get() {
                return collect([(object) ['id' => 1, 'code' => 'samsung']]);
            }
        });
    
    $products = DB::table('products')->get();
    
    $this->assertEquals(1, count($products));
    
    Login or Signup to reply.
  2. I would strongly suggest to NOT mock any DB calls, why? Laravel has events, scopes, attributes, etc behind scenes (that you can set), and if you mock one method, maybe a scope is not applied, or anything else, so I always suggest NOT mocking the database.

    It is easier to set up a clean test database and migrate it and when all the tests are done, do something with it, than mocking calls and whatever from either DB facade or a or more than one class extending Model.

    You can check my profile, I do have some links in there related to other StackOverflow questions about testing, that may help you a lot in general.


    Which one is easier for you (I am going to use @Abdulla Nilam‘s example):

    DB::shouldReceive('table')
        ->once()
        ->with('products')
        ->andReturn(new class {
            public function get() {
                return collect([(object) ['id' => 1, 'code' => 'samsung']]);
            }
        });
    
    $products = DB::table('products')->get();
    
    $this->assertEquals(1, count($products));
    

    Or this more "laravel way" approach:

    // This call hypothetically creates a Product
    $this->post('/your/url')
        ->assertCreated();
    
    $this->assertNotEmpty(Product::all());
    

    Of course, these are super simple examples, but 99.9% of the time do not mock database calls at all. You definitely can, but you are very prone to mock something that Laravel processes on the back, as I said before, maybe an event, a scope, an attribute casting, etc.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search