5

I'm writing my unit tests and by default they should not hit the database. by general rule I always use eloquent to get the results, but some more complex queries I have to use the raw DB

I have this function:

public function GetPassword($email)
{
    $result = DB::table('vin_user_active')
        ->select(
            "vin_user_active.id",
            "vin_user_active.password",
            DB::raw('COALESCE(
                vin_user_active.pass_update_date <=
                CURRENT_TIMESTAMP -
                INTERVAL vin_org_active.password_expiration_days DAY, 0
        ) AS password_expired')
        )
        ->join('vin_org_active', "vin_user_active.org", "=", "vin_org_active.id")
        ->where("email", "=", $email)
        ->first();

    return $result;
}

Right now I'm mocking the GetPassword function, but 1. I think the function should be private, not public. 2. The coverage is just %50 because is skipping the whole function.

How would I mock it? right now I have this

$this->db =Mockery::mock('Illuminate\Database\Query\Builder')->makePartial();

    DB::shouldReceive('table')
        ->once()
        ->with("vin_user_active")
        ->andReturn($this->db);

    DB::shouldReceive('raw')
        ->once()
        ->with(Mockery::any())
        ->andReturn(true);

    DB::shouldReceive('select')
        ->once()
        ->with("vin_user_active.id,
            vin_user_active.password,
            DB::raw('COALESCE(
                vin_user_active.pass_update_date <=
                CURRENT_TIMESTAMP -
                INTERVAL vin_org_active.password_expiration_days DAY, 0
        ) AS password_expired'")
        ->andReturn($this->db);

I honestly have no idea what I'm doing, I've never mocked so many levels of function calls.

any idea?

Daniel Angel
  • 489
  • 1
  • 6
  • 14
  • You should NOT mock laravel facades, also, you can hit the database in your tests, only thing to take note at is to use transactions so that your db queries are not persisted. – Mahmoud Tantawy Jan 25 '16 at 20:40
  • For more info check, https://laracasts.com/series/phpunit-testing-in-laravel – Mahmoud Tantawy Jan 25 '16 at 20:41
  • 2
    I try to stay away from touching the database in unit testing (apart from that I have my integration tests that uses database transactions) – Daniel Angel Jan 28 '16 at 20:43
  • I understand, but what is the point of mocking the database and wasting all that time to stay away from touching the database? – Mahmoud Tantawy Jan 28 '16 at 20:49
  • 9
    @MahmoudTantawy if you have thousands of tests, you can not wait until real queries are running, you need to mock them like any other side effects (API calls, etc), so it is bad to touch real database in tests. – aeryaguzov Mar 18 '16 at 10:06
  • @MahmoudTantawy I have an issue with MySQL sort (ie. its not defined). The data returned may not always be in the same order if I use MySQL so I want to mock the data in a way (sorted) that replicates the bug so that I can confidently verify that its fixed. I don't suppose you got anywhere this this Daniel? – micmania1 Feb 02 '17 at 04:41
  • 4
    So much one can learn in a year, now i see how my comment was kinda stupid. – Mahmoud Tantawy Feb 02 '17 at 09:05
  • @micmania1 to replicate randomness is hard, but may be this will let you understand more http://stackoverflow.com/questions/6662837/how-mysql-order-the-rows-with-same-values – Mahmoud Tantawy Feb 02 '17 at 09:05

2 Answers2

10

Actually it was simple enough

    DB::shouldReceive("raw")
        ->set('query', 'query test')
        ->andReturn(true);
Daniel Angel
  • 489
  • 1
  • 6
  • 14
0

Quite late answer but there you go:

DB::spy()

Motassem Kassab
  • 1,744
  • 4
  • 21
  • 40