test API with phpunit laravel 5.2 - php

so I have created a test class in /test directory
in a testExample function, I have store input and output JSON string into a variable.
converted input and output strings to array by using
json_decode(inputstring, true); json_decode(outputstring, true);
I have used following to test this API
$this->json('POST', 'api/v1/tagging', $input, ['Content-Type' => 'application/json'])
->seeJson([
'conversion_specs' => ["post_engagement"],
]);
Where conversion_specs: ["post_engagement"] is one of the section of output json
how could I assert it and it is printing too much data after hitting
./vendor/bin/phpunit command
I think it's going wrong, can anyone help me to check an API with expected value.

Related

Laravel Exception handler logs also the request

I'm working on a Laravel 5.8 project, and I want to log inside the daily log file the request that has caused the exception, if some exception occurs.
I've tried this in the public function report(Exception $exception)
parent::render(request());
but it doesn't work at all. I've also tried this
\Log::error(json_encode(request()));
But it logs this
local.ERROR: {"attributes":{},"request":{},"query":{},"server":{},"files":{},"cookies":{},"headers":{}}
How should i do it? I need it in order to understand which request has caused that exception, and if it's possible, i need to log also other values, but i think that solved this, i can reuse the code to logs also the others
You can't just json_encode() the entire request as many properties are private/protected and require the use of getters for access. You will need to determine which values are important to you and build an appropriate response.
$response = [
'method' => request()->method(),
'url' => request()->url(),
'full_url' => request()->fullUrl(),
'data' => request()->all(),
];
Then you can pass your response array as a second parameter to the log handler, without needing to use json_encode().
\Log::error('Request details: ', $response);

Laravel dispatch plain json on queue

I have 2 simple questions overall. Im currently looking into some event handling in Laravel and would like to use RabbitMQ as my event store. Therefor i installed this package to start with: https://github.com/php-enqueue/enqueue-dev
To get started i registered it and i am able to push messages on to RabbitMQ:
$job = (new Sendemail())->onQueue('email')->onConnection('interop');
dispatch($job);
The problem however is that Laravel pushes a certain format on the queue and i can't figure out how to change that. An example message would be:
{
"job":"Illuminate\\\\Queue\\\\CallQueuedHandler#call",
"data":{
"command":"O:29:\\"Acme\\Jobs\\FooJob\\":4:{s:11:\\"fooBar\\";s:7:\\"abc-123\\";s:5:\\"queue\\";N;s:5:\\"delay\\";N;s:6:\\"\\u0000*\\u0000job\\";N;}"
}
}
So the question is, how can i change this? The main reason on this is that the consumer side is not even a PHP application which also can not interpret the PHP serialized model. Therefor im looking for a way to push a plain JSON object instead.
From the other hand i would also like to understand how you could build a custom listener? For the listener the same thing happens. Laravel tries to read the method but when i push plain JSON this will never work. Isn't there a way to register a handler on a topic and do further handling of the payload of the message within the handler itself?
There is a simple way for your purpose:
First install this package for rabbit:
vladimir-yuldashev/laravel-queue-rabbitmq
and in controller:
Queue::connection('rabbitmq')->pushRaw('{you can generate a json format here}', 'queue_name');
you can generate a json and put in this command.
There's a laravel-queue library that works with the php-enqueue library you linked to make it compatible with Laravel's built in queue system that Florian mentioned.
By default, it will still use a serialized object, but I think that can be overridden. If you look in Queue.php, createObjectPayload() on line 130 in the core Laravel Framework, that's where the job is being serialized.
If you extend the Queue class in the laravel-queue library, you should be able to change createObjectPayload to look something like this:
protected function createObjectPayload($job, $queue)
{
$payload = $this->withCreatePayloadHooks($queue, [
'displayName' => $this->getDisplayName($job),
'job' => 'Illuminate\Queue\CallQueuedHandler#call',
'maxTries' => $job->tries ?? null,
'timeout' => $job->timeout ?? null,
'timeoutAt' => $this->getJobExpiration($job),
'data' => [
'commandName' => $job,
'command' => $job,
],
]);
return array_merge($payload, [
'data' => [
'commandName' => get_class($job),
'command' => json_encode(clone $job),
],
]);
}
That should JSON encode the job data instead of serializing it. You may even be able to remove the encoding altogether, as I think it's already JSON encoded somewhere up the chain.

$request->all() in laravel returns empty when called from phpunit

I am trying to write phpunit test cases in Laravel, the problem is the functionality works perfectly fine but when I try to access via phpunit the $request->all() always returns empty.
$request->request->add(['testId' => 1]);
This is called using
$request->all();
This when called in the Laravel application works as expected and gives the data. But when called via terminal using phpunit it always returns empty array. But it returns the data if called as
$request->request->all();
Please let me know how can this be solved. Laravel verison used is Laravel Framework 5.6.24
I am manually creating a request in Phpunit test file as:
use Illuminate\Http\Request as Request;
$request = new Request();
Test Class:
use Tests\TestCase;
use App\Http\Middleware\Authenticate;
class BasicTest extends TestCase
{
public function testMyfunc()
{
$request = new Request();
$request->setMethod('GET');
$request->headers->set('key','value');
$request->request->add(['testId' => 1]);
print_r($request->all()); //This is returning empty array always
print_r($request->request->all()); //This returns correct data
//But I need to get the GET params when I call $request->all()
}
}
You are to add the data to QUERY!
$request->query->add(['testId' => 1]);
It worked for me this way only ... in addition to
$request->request->replace(['testId' => 1]);
But the last line served for other re-requests, so probably, it to work even without it.

Laravel testing assertions against session and response

When testing a route in Laravel I cannot seem to assert against both the returned response and the session. Is there any reason for this and should I instead be splitting the test into two?
Here's my test, simplified:
$response = $this->call('POST', route('some-route'), $data);
This passes:
$this->assertResponseStatus(302);
This doesn't pass:
$this
->assertResponseStatus(302)
->assertSessionHasErrors([
'application_status' => 'Application status has changed. Action not applied.'
]);
The test will throw up an error saying it can't assert against null.
I've tried moving the order of the tests round and also assigning the response and session to variables before asserting like so:
$response = $this->call('POST', route('admin.application.action.store'), $data);
$sessionErrors = session()->get('errors');
$this
->assertEquals(302, $response->status())
->assertTrue($sessionErrors->has('application_status'));
But still get the same issue. Error: Call to a member function assertTrue() on null
Any advice would be greatly appreciated. Thanks!
Assertions don't implement fluid interface. Run it as 2 sequential statements:
$this->assertResponseStatus(302);
$this->assertSessionHasErrors([
'application_status' => 'Application status has changed. Action not applied.'
]);

Error testing Restful API in Laravel using PHPUnit

Our team has created a Restful API using laravel. We are doing unit testing on the api using PHPUNIT but encountered a problem on testing a POST request.
Here is the code:
public function create_new_account()
{
$account = array (
'accountName'=>$this->fake->word,
'contactName'=>$this->fake->name,
'contactEmail'=>$this->fake->email,
'address'=>$this->fake->sentence
);
$accounts = json_encode($account);
$this->call('POST','accounts',$accounts);
$this->assertResponseOk();
}
This tests if we can create an account using API but I'm always getting an errror
1) ApiServicesTest::create_new_account
ErrorException: Argument 2 passed to Symfony\Component\HttpFoundation\Request::createRequestFromFactory() must be of the type array, string given, called in /var/www/mcx-api/vendor/symfony/http-foundation/Request.php on line 421 and defined
/var/www/mcx-api/vendor/symfony/http-foundation/Request.php:1999
/var/www/mcx-api/vendor/symfony/http-foundation/Request.php:421
/var/www/mcx-api/vendor/laravel/framework/src/Illuminate/Foundation/Testing/CrawlerTrait.php:775
/var/www/mcx-api/tests/ApiServicesTest.php:35
When you test the api using a client like httprequester/postman it is working fine. The api is required to be passed a JSON data so if I passed the array the api is inserting null values. But when I converted the data to json I get the error above. When I tried dd($accounts) here is the output
"{"accountName":"rerum","contactName":"Ms. Mireille Veum Jr.","contactEmail":"Lindgren.Damaris#gmail.com","address":"Vel quidem consectetur nemo excepturi quod."}"
which means data is converted to json format and should be accepted by the api however I don't get what laravel is complaining. Can somebody point me to where I'm doing it wrong? Thank you very much!
Try sending the json as the content.
$this->call('POST', 'accounts', [], [], [], [], $accounts)

Categories