UnitTest Closure in Query Builder with Mockery

Submitted by fenos - 5 years ago

With this trick you will able to unitTest complex query, that will have closures.

public function selectSomething()
{
    return $this->user->join('table2', function($join){
    
    $join->on('table2.id','=','table1.id');
    
    })->where('something','=',1)->orWhere(function($query){
        
        $query->where('something','>',10);
        
    })->get();
}

public function testSelectSomething()
{
    $mockUserModel = m::mock('User');
    
    // Unit test The First Join
    $mockUserModel->shouldReceive('join')
        ->once()
        ->with('table2', m::on(function($join){
            // Unit Test Closure
            $mockDb = m::mock('Illuminate\Database\DatabaseManager');
            
            $subQuery = $mockDb->shouldReceive('on')
                ->once()
                ->with('table2.id','=','table1.id')
                ->andReturn($mockDb);
                
            $join($subQuery);
            
            return true;
            
        }))->andReturn($mockUserModel);
        
        // Unit Test Where
        $mockUserModel->shouldReceive('where')
            ->once()
            ->with('something','=',1)
            ->andReturn($mockUserModel);
            
        $mockUserModel->shouldReceive('orWhere')
            ->once()
            ->with(m::on(function($orWhere){
                    
                // Unit Test Closure
                $mockDb = m::mock('Illuminate\Database\DatabaseManager');
                
                $subQuery = $mockDb->shouldReceive('where')
                    ->once()
                    ->with('something','>',10)
                    ->andReturn($mockDb);
                    
                $orWhere($subQuery);
                
                return true;
                    
            }))->andReturn($mockUserModel);
            
            $result = $this->class->selectSomething();
            
            $this->assertInstanceOf('User',$result)
}