I'm writing unit tests for an API using PHPUnit and Laravel. Most functions I'm testing require that the user is authenticated before the function can be ran. The user data is stored in one table, and their permissions are stored inside of another table. I can fake the user object inside of Laravel, but I need to be able to also pull the corresponding permissions from the other table without having to hit the database like the dingo router currently is doing.
Currently running Laravel 5.8 and PHPUnit 8.1.5. I currently have the users object that I generated from a Laravel factory saved to a text file. I am able to pass that to a function called "actingAsApi" (found on Github, code below) and that allows me to authenticate as that user. However, the function is still going out and getting all permissions for that user from the database. I'm trying to mock or fake the permissions object it is pulling somewhere so that it doesn't need to hit the database at all. I also tried using the built in Passport functions for Passport::actingAs, and those did not work either as they were still hitting the DB (and not really working anyways).
actingAsApi (inside of TestCase.php)
protected function actingAsApi($user)
{
// mock service middleware
$auth = Mockery::mock('Dingo\Api\Http\Middleware\Auth[handle]',
[
Mockery::mock('Dingo\Api\Routing\Router'),
Mockery::mock('Dingo\Api\Auth\Auth'),
]);
$auth->shouldReceive('handle')
->andReturnUsing(function ($request, \Closure $next) {
return $next($request);
});
$this->app->instance('Dingo\Api\Http\Middleware\Auth', $auth);
$auth = Mockery::mock('Dingo\Api\Auth\Auth[user]',
[
app('Dingo\Api\Routing\Router'),
app('Illuminate\Container\Container'),
[],
]);
$auth->shouldReceive('user')
->andReturnUsing(function () use ($user) {
return $user;
});
$this->app->instance('Dingo\Api\Auth\Auth', $auth);
return $this;
}
Test inside of my Test file
public function testActAs() {
$user = 'tests/users/user1.txt';
$this->actingAsApi($user);
$request = new Request;
$t = new TestController($request);
$test = $t->index($request);
}
I expect the actingAsApi function to allow me to also pass in the mock permissions data that corresponds to my mock user object data from the file, but instead it is hitting the database to pull from the permissions table.
EDIT:
So i've been playing around with doing mock objects, and i figured out how to mock the original controller here:
$controlMock = Mockery::mock('App\Http\Controllers\Controller', [$request])->makePartial();
$controlMock->shouldReceive('userHasPermission')
->with('API_ACCESS')
->andReturn(true);
$this->app->instance('App\Http\Controllers\Controller', $controlMock);
but now I can't figure out how to get my call from the other controllers to hit the mocked controller and not a real one. Here is my code for hitting an example controller:
$info = $this->app->make('App\API\Controllers\InfoController');
print_r($info->getInfo('12345'));
How can i make the second block of code hit the mocked controller and not standup a real one like it does in its constructor method?