I have a controller which is getting an instance of Illuminate\Http\Request injected through the constructor. Now I need to write an unit test that test a call in the controller which uses the values from the Request instance. I have decided to use Faker. How to use Faker to generate an associative array so that I can use the array in my test case like,
$this->post('the_uri','MyFakerArray')
And the dynamic array will automatically be available in my controllers request.
There is no need to fake/mock the Request object.
When you are simulating a request laravel does that for you, it create a request to the url you request and pass the variables, then you get back the response from your application.
For example:
$response = $this->call('POST', '/user', ['name' => 'Taylor']);
now the $response variable has the data to test on.
I think you have:
getContent() // for getting the reponse body
getCode() // for http code: 200, 401 etc
When you do that, your tests should work with the response, you have no need for Faker in this situation.
Related
Can anyone explain if there is a reason why we should not be using getting the authenticated user within a from request authorize method, via the Auth::user() or auth()->user() helpers vs. the $this->user() method as suggested in docs?
https://laravel.com/docs/5.8/validation#authorizing-form-requests
In my case, I am trying to unit test a form request and auth()->user() allows me to retrieve the user whereas $this->user() does not as I am not making a full request. I am just creating the form request object for my test.
public function setUp(): void
{
parent::setUp();
$this->subject = new \App\Http\Requests\OrderStoreRequest();
}
// Acting as has no effect when manually creating the orderStoreRequest object
public function testAuthorize()
{
$this
->actingAs(\factory(User::class)->create())
->assertTrue($this->subject->authorize());
}
ActingAs() is calling the Laravel Auth system, which in the request lifecycle is put into the request (See). Since you are just calling your request without this lifecycle, you will never get anything injected into the Request.
For your code to work, you need to set the UserResolver. This can be done like so.
$this->subject->setUserResolver(function () use($user) {
return $user;
});
For ease of usage, i would highly recommend doing Laravel feature tests instead of unit testing. You are gonna fight your way through a lot of approaches, there is not meant to be called without the Laravel lifecycle. Which you will get doing call() and json() on the app.
I have a function which requires the url to be able to work. I am trying to unit test it as its behaviour changes depending on the url query parameters.
MyServiceTest.php
function testMyTestFunction() {
$service = new MyService();
// Some how change the url for the app. This doesn't work
config(['app.url' => 'http://test.test?myNewParam=5']);
$service->test();
}
MyService.php
function test() {
// Does not contain `myNewParam`
$url = url()->full();
// do some logic
}
I've also tried mocking the request as that's what the url() helper function references but I've had no luck in doing this successfully.
When you use url()->full(); this returns the current request full URL, not the one set in the config. So when using this:
config(['app.url' => 'http://test.test?myNewParam=5']);
then you can get the value like this: config('app.url').
If you want to get the param through the url helper then you will need to make a request to the controller route that uses your service, for example:
$this->get('/test?myNewParam=5')->assert...
but then that would not be a unit test. You should better move out the usage of your url helper function from within your service method and provide that as a dependency to the service. That way you can use one url for your production code and another for your test code.
In other MVC frameworks, accessing to the current request object is as simple as $this->request. However in the Laravel, I generally see that Request $request is generally injected to each action (public function edit($id, Request $request)). It seems like a boilerplate. Is there any better way to access the request? (I now that I can use inheritance to use $this->request, I am looking for the Laravel way to do that.)
update:
I found out using app('request') I can access to the current request. However, I am not sure of its potential pros and cons.
In Laravel 5, you can use the request() helper:
// to get the current request object
$request = request();
// or to just get a value from the request
$value = request("field", "default");
See https://laravel.com/docs/5.6/helpers#method-request
PSR-7 is going to be standardized soon (I believe). That's got me thinking about middlewares, such as used by Phly, StackPHP, and ConnectJS.
The way ConnectJS works is that it modifies the request object when a middleware needs to add something. For example, cookie-session creates a session property on the req object:
app.use(session({
keys: ['key1', 'key2']
}))
app.use(function (req, res, next) {
var n = req.session.views || 0 // <-- req.session is managed by the session middleware
req.session.views = ++n
res.end(n + ' views')
})
With PSR-7, both our Request and Response objects are (supposed to be) immutable, so how are we supposed to pass along additional data like this? i.e. where would be the best place to store a 'session' object or a 'user' object created by an authentication middleware?
Request and Response objects in PSR-7 are implemented as value objects, hence they are immutable.
Every time you need a different object, you create a new instance from the previous one, like
$newRequest = $oldRequest->withMethod('GET');
and from that point on use the new instance.
In middlewares you would have to pass the new instance to the next() function that calls the next middleware (see here for example).
If you need to store in the request object additional data computed from your current request, in the ServerRequestInterface there are defined the withAttribute and the withAttributes methods that allow you to do exactly that.
A common use case for this is for storing the results of routing, but you can surely use them to store other additional data of the request, like session or user data
Do not store at all. Inject it as parameter into consumer function. For instance:
function doSomething(reqest, response, session, user, foo, bar, ...)
Be explicit.
I am using league/route to handle routing for my application.
I have a post route:
$router = new RouteCollection;
$router->post('/url', 'MyClass::myMethod');
...$dispatcher->dispatch(...)->send();
In my method:
class MyClass {
public function myMethod(Request $request) {
var_dump($request->request);
}
}
Var dumping the passed request object is just a fresh instance of HttpFoundation\Request, and not the actual request that the application has processed, i.e, there is no post data. To get the post data, I need to do:
$request = Request::createFromGlobals();
Within my method. This makes the passed request object to my method useless. How can I configure Route to pass the actual request so I can get my post data, without having to create my own request object?
The RouteCollection object accepts a dependency of league/container, a dependency injection container. This is where the Request object is pulled from when invoking your controller.
By design the request object is not built for you in case you would like to do anything specific with it yourself, so for this reason, it needs to be defined within the container or will return you a blank request each time. It is planned for this to be remedied in version 2 of the router due in the not too distant future of me posting this.
So something like this is required.
<?php
$container = new League\Container\Container;
$container->add('Symfony\Component\HttpFoundation\Request', function () {
return Symfony\Component\HttpFoundation\Request::createFromGlobals();
});
$router = new League\Route\RouteCollection($container);
$router->post('/url', 'MyClass::myMethod');
// ...
$dispatcher->dispatch(/* ... */)->send();