Laravel provides us with a range of test helper methods as part of the framework, and some of the crucial ones that we are using on a daily basis are sitting a trait name MakesHttpRequests
. These are methods we are using to send a request to our application and eventually make an assertion against the response or the actions that happened.
But you may notice the get
method on MakesHttpRequests
does not support query string (parameters):
/** * Visit the given URI with a GET request. * * @param string $uri * @param array $headers * @return \Illuminate\Testing\TestResponse */ public function get($uri, array $headers = []) { $server = $this->transformHeadersToServerVars($headers); $cookies = $this->prepareCookiesForRequest(); return $this->call('GET', $uri, [], $cookies, [], $server); }
As you see the third parameter for call
method is an empty array.
This could be a problem for you if you are trying to test a route that accepts query strings. Let me show you 3 options to overcome this issue:
1- Use CALL method instead of GET
If you look at the underlying code of the get
method you notice it delegates the action to the call
method at the end. So what we can do is to use that method in our test.
/** @test */ public function it_searches_users_using_query_string() { $this->call('GET', '/users', ['search' => 'houmaan']) ->assertSuccessful() ->assertSee('houmaan'); }
2- Override GET method
Although, option 1 might work but we ignored two methods are called in base get
method:
$server = $this->transformHeadersToServerVars($headers); $cookies = $this->prepareCookiesForRequest();
As the method names clearly convey what they do we want to make sure we call them as part of get
request, so what you can do is to override the get
method in our TestCase
and add an additional argument for parameters:
abstract class TestCase extends BaseTestCase { use CreatesApplication; public function get($uri, array $parameters = [], array $headers = []) { $server = $this->transformHeadersToServerVars($headers); $cookies = $this->prepareCookiesForRequest(); return $this->call('GET', $uri, $parameters, $cookies, [], $server); } }
Now we can call get
method in our test like this:
/** @test */ public function it_searches_users_using_query_string() { $this->get('/users', ['search' => 'houmaan']) ->assertSuccessful() ->assertSee('houmaan'); }
3- Use route helper method
The last option, and it’s the option I personally take, is to name our route and use the helper to attach query string to it. So by using name
method on the route file we can assign a name to our route:
Route::get('/users', 'UsersController@index')->name('users.index');
And then simply you can use route helper function on our test and pass an array of parameters as the second argument.
/** @test */ public function it_searches_users_using_query_string() { $this->get(route('users.index', ['search' => 'houmaan'])) ->assertSuccessful() ->assertSee('houmaan'); }
So what route
helper method did for us here is to lookup the key users.index
in the routes, find the url, transform the array of parameters (second argument) to query string and attach to it.
Conclusion
Although all 3 options could be valid, I lean more toward option 3! Because not only it solves my problem with the get
method, having a name for your routes will free you from remembering all cryptic routes in your application, plus by the time you want to refactor or rename a route, tests could remain unchanged.
Be First to Comment