Cannot test validation errors in Lumen - php

When i try to validate controller response using one of the available assertions like assertJsonValidationErrors it gives the following error:
Failed to find a validation error in the response for key: 'name'
Here is my test:
Mesh::factory()->create(['name'=>'test']);
$this->post(route('meshes.store', ['name' => 'test']));
$this->response->assertUnprocessable()->assertJsonValidationErrors('name');

Validation response format in Lumen is different than Laravel which wraps the errors in errors property.
Simply pass null to the second parameter of assertJsonValidationErrors or any other methods available for validation assertion which has this parameter and you should be fine:
$this->response->assertUnprocessable()->assertJsonValidationErrors('name', null);

Related

"Trying to get property of non-object" error when running a Codeception test

I have a Cest with a _before() that has the following code in it to authenticate (API testing):
// Log a user in
$I->haveHttpHeader('Accept', 'application/json');
$I->sendPOST('/authentication/login', ['username' => $this->username, 'password' => $this->password]);
$this->api_token = json_decode($I->grabResponse())->token;
When I run the test I get the following error:
[PHPUnit_Framework_Exception] Trying to get property of non-object
Scenario Steps:
3. $I->grabResponse() at tests/api/ApiBase.php:19
2. $I->sendPOST("/authentication/login",{"username":"user#examplecom","password":"abc123"}) at tests/api/ApiBase.php:17
1. $I->haveHttpHeader("Accept","application/json") at tests/api/ApiBase.php:16
tests/api/ApiBase.php:19 is $this->api_token = json_decode($I->grabResponse())->token;
It appears as if $I is no longer an object, but I have confirmed that it is still an instance of ApiTester. So the only thing I can think of is the call to the property of a non-object is somewhere deeper down.
How can I tell where? I'm running this with the --debug switch enabled.
[EDIT] This isn't a problem with the json_decode. If I move $I->grabResponse() up then the error will be on that line.
Validate response before using it.
seeResponseJsonMatchesJsonPath checks if the element is present in json response.
$I->seeResponseJsonMatchesJsonPath('$.token');
Also it could be useful to use grabDataFromResponseByJsonPath method instead of parsing it yourself.
$this->api_token = $I->grabDataFromResponseByJsonPath('$.token')[0];
[0] is necessary because grabDataFromResponseByJsonPath returns a list of matching items.
You may need to install flow/jsonpath library to get JsonPath methods working if it isn't installed yet.

Symfony: type error when using flash bag in controller

In order to get the flash bag of the session and add a flash message, in the controller I call:
$request->getSession()->getFlashBag()->addFlash(...);
(where $request is an instance of Request)
but I get the following IDE type error:
Method 'getFlashBag' not found in
null|\Symfony\Component\HttpFoundation\Session\SessionInterface
The problem is that $request->getSession() returns a SessionInterface, which does not contain the getFlashBag method.
That's why the IDE is complaining, even if the actual object returned by that method is an instance of the Session class which has the getFlashBag method.
When inside a controller, a quick solution can just be using:
$this->addFlash(...);
instead of:
$request->getSession()->getFlashBag()->addFlash(...);

Testing Exceptions in PHPUnit

I am new to unit testing and now trying to write some test cases using PHPUnit for a Laravel application. I have done one basic test which is like the following :
public function testGetPointsByApp()
{
$this
->json(
'GET',
self::URL.'/'.$value
)
->assertResponseStatus(200)
->seeJson([
'status' => 'success',
])
->seeJsonStructure([
'status',
'message',
'data' => []
]);
}
Now this is working. But I would like to know how can I test for invalid inputs and for the cases like there is not data at all with the given parameters. I am throwing corresponding exceptions in each of these cases and it will add particular messages. How can I test whether it is thrown ?
I don't want to include it to this method and would like to write some other methods to test different scenarios in the API like invalid UUID, no data etc. So for each time, I need to call the API url or this call can be done from any kind of set up function ?
I don't know laravel but in PHPUNIT you can test if exception is thrown with expectException function. For example for InvalidArgumentException
$this->expectException(InvalidArgumentException::class);
You can also use annotation #expectedException and there are also a lot of things that can be tested in exception like expectExceptionCode() etc.
More you can find here
Since you're not doing an Unit test (this kind of test you're doing is an acceptance test), you cannot check for the exception it self, you will look for a bad response:
$this
->json(
'GET',
self::URL.'/'.$BAD_VALUE
)
->assertResponseStatus(422)
->seeJson([
/* Whatever you want to receive at invalid request */
])
->seeJsonStructure([
/* Whatever you want to receive at invalid request */
]);
Laravel validation errors returns 422 - unprocessable entity HTTP code.
You can check the response also for your expected error messages or something else.

How to mock Cache::remember in Laravel

Within a unit test method, I tried to mock a Cache::remember response like this:
Cache::shouldReceive('remember')
->once()
->with('my_key', 120, function() {}) // There are 3 args in remember method
->andReturn([]);
But I get this error:
exception 'Mockery\Exception\NoMatchingExpectationException'
with message 'No matching handler found for
Mockery_0_Illuminate_Cache_CacheManager::remember
("my_key", 120, object(Closure)). Either the method was
unexpected or its arguments matched no expected argument
list for this method
I don't understand why I got this error and did not found anything in Laravel documentation about this. It says there is no matching, but it seems to match.
How can I mock a Cache::remember response?
replace 3rd argument of with method to \Closure::class to matching any closures.
Cache::shouldReceive('remember')
->once()
->with('my_key', 120, \Closure::class)
->andReturn([]);
See this issue about challenges with mocking the Cache facade -
https://github.com/laravel/framework/issues/10803
also reference
https://github.com/laravel/framework/issues/9729

Laravel 5.1 + PHPunit - API test returns always invalid argument error foreach

I've upgraded from Laravel 5.0 to 5.1
Test suite works fine and I can run the phpunit command. But, when I'm start to test with the api test, I always get a foreach error.
class ExampleTest extends TestCase {
public function testLoginCredentials()
{
$this->post('/srv/plc/auth/login', ['data' => 'some data'])
->seeJson([
'authorized' => true,
]);
}
}
Above looks like the documentation: http://laravel.com/docs/5.1/testing#testing-json-apis
If I run my test via phpunit, I get the following error:
There was 1 error:
1) ExampleTest::testBasicExample
ErrorException: Invalid argument supplied for foreach()
/Applications/XAMPP/xamppfiles/htdocs/w/server/vendor/framework/src/Illuminate/Support/Arr.php:423
/Applications/XAMPP/xamppfiles/htdocs/w/server/vendor/framework/src/Illuminate/Support/helpers.php:301
/Applications/XAMPP/xamppfiles/htdocs/w/server/vendor/framework/src/Illuminate/Foundation/Testing/CrawlerTrait.php:365
/Applications/XAMPP/xamppfiles/htdocs/whennn/server/vendor/laravel/framework/src/Illuminate/Foundation/Testing/CrawlerTrait.php:352
/Applications/XAMPP/xamppfiles/htdocs/whennn/server/tests/ExampleTest.php:17
/Applications/XAMPP/xamppfiles/lib/php/PHPUnit/TextUI/Command.php:188
/Applications/XAMPP/xamppfiles/lib/php/PHPUnit/TextUI/Command.php:126
FAILURES!
Tests: 1, Assertions: 0, Errors: 1.
If I do a get request with $this->get, I get the same error. Same error with other endpoints.
$this->visit works fine.
After a lot of debugging....
seeJson() only accepts an Json array (not Json object)
Foreach error appears when the tested endpoint not returns an array. If there's more than an array, the error appears.
I really don't know why seeJson must be an array.
I expected an 'assertion error', instead of an foreach error

Categories