Skip to content

Instantly share code, notes, and snippets.

@nisevi
Last active March 13, 2017 22:52
Show Gist options
  • Save nisevi/fcd006d25ca297b49d52fb363e374757 to your computer and use it in GitHub Desktop.
Save nisevi/fcd006d25ca297b49d52fb363e374757 to your computer and use it in GitHub Desktop.
How to check the keys of a JSON in PHP?

Since I had problems trying to implement the method "seeJsonStructure" as you will see here: phpunit error "must be a array or ArrayAccess" -> laravel/framework#18280

I just wanted and alternative to check the keys of the json that I receive from the Laravel API that I created.

The things to pay atention on "composer.json" are:

...
    "autoload": {
        "classmap": [
            "database"
        ],
        "psr-4": {
            "App\\": "app/"
        }
    },
...

on "tests/Traits/ApiTestTrait.php":

...
public function validateKeys($actualData, $expectedData)
{
    foreach ($actualData as $key => $value) {
        if (is_array($value)){
            $this->validateKeys($value, $expectedData);
        } else {
            $this->assertContains($key, $expectedData);
        }
    }
}

public function validateCountKeys($actualData, $expectedData)
{
    $this->assertCount(count($expectedData), $this->getKeys($actualData));
}

private function getKeys($actualData)
{
    $keys = array();
    foreach ($actualData as $key => $value) {
        if (is_array($value)){
          $keys = array_merge($keys, $this->getKeys($value, $keys));
        } elseif (!array_key_exists($key, $keys)){
          $keys[] = $key;
        }
    }
    return array_unique($keys);
}
...

Just a little clarification about these methods:

"validateKeys" -> it will recursively iterate a multidimensional array evaluating each "key" with "value" different from an array. If the "value" is an array then we can evaluate the "keys" of "value" and not the "key" itself.

"validateCountKeys" -> It will give us all the keys of a multidimentional array where the value of a key is not an array. After getting all the keys I just do "array_unique" for eliminating duplicated items.

on "tests/api/UserControllerTest.php":

...
use Tests\Traits\ApiTestTrait;
...
use ApiTestTrait;
...
$this->validateKeys($paginatedUsers, $paginationAndUserKeys);
$this->validateCountKeys($paginatedUsers, $paginationAndUserKeys);
...

I encourage you to help me if you think this could have been done in a different way.

<?php
namespace Tests\Traits;
trait ApiTestTrait
{
public function assertApiResponse(Array $actualData)
{
$this->assertApiSuccess();
$response = json_decode($this->response->getContent(), true);
$responseData = $response['data'];
$this->assertNotEmpty($responseData['id']);
$this->assertModelData($actualData, $responseData);
}
public function assertApiSuccess()
{
$this->assertResponseOk();
$this->seeJson(['success' => true]);
}
public function assertModelData(Array $actualData, Array $expectedData)
{
foreach ($actualData as $key => $value) {
$this->assertEquals($actualData[$key], $expectedData[$key]);
}
}
public function validateKeys($actualData, $expectedData)
{
foreach ($actualData as $key => $value) {
if (is_array($value)){
$this->validateKeys($value, $expectedData);
} else {
$this->assertContains($key, $expectedData);
}
}
}
public function validateCountKeys($actualData, $expectedData)
{
$this->assertCount(count($expectedData), $this->getKeys($actualData));
}
private function getKeys($actualData)
{
$keys = array();
foreach ($actualData as $key => $value) {
if (is_array($value)){
$keys = array_merge($keys, $this->getKeys($value, $keys));
} elseif (!array_key_exists($key, $keys)){
$keys[] = $key;
}
}
return array_unique($keys);
}
}
{
"name": "laravel/laravel",
"description": "The Laravel Framework.",
"keywords": ["framework", "laravel"],
"license": "MIT",
"type": "project",
"require": {
"php": "^7.1.0",
"laravel/framework": "5.3.*",
"barryvdh/laravel-ide-helper": "v2.2.1",
"laravelcollective/html": "v5.3.0",
"laravel/cashier-braintree": "v2.0.2",
"infyomlabs/laravel-generator": "5.3.x-dev",
"infyomlabs/core-templates": "5.3.x-dev",
"infyomlabs/swagger-generator": "dev-master",
"jlapp/swaggervel": "2.0.x-dev",
"doctrine/dbal": "2.3.5",
"league/flysystem-aws-s3-v3": "1.0.13",
"tymon/jwt-auth": "0.5.9",
"barryvdh/laravel-cors": "v0.8.2",
"fzaninotto/faker": "~1.4",
"caouecs/laravel-lang": "3.0.19"
},
"require-dev": {
"fzaninotto/faker": "~1.4",
"mockery/mockery": "0.9.*",
"phpunit/phpunit": "~5.7",
"symfony/css-selector": "3.1.*",
"symfony/dom-crawler": "3.1.*"
},
"autoload": {
"classmap": [
"database"
],
"psr-4": {
"App\\": "app/"
}
},
"autoload-dev": {
"classmap": [
"tests/TestCase.php"
],
"psr-4": {
"Tests\\": "tests/"
}
},
"scripts": {
"post-root-package-install": [
"php -r \"file_exists('.env') || copy('.env.example', '.env');\""
],
"post-create-project-cmd": [
"php artisan key:generate"
],
"post-install-cmd": [
"Illuminate\\Foundation\\ComposerScripts::postInstall",
"php artisan optimize"
],
"post-update-cmd": [
"Illuminate\\Foundation\\ComposerScripts::postUpdate",
"php artisan optimize"
]
},
"config": {
"preferred-install": "dist"
}
}
<?php
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use App\Models\User;
use App\Models\Role;
use Tests\Traits\ApiTestTrait;
class UserControllerTest extends TestCase
{
use ApiTestTrait;
use DatabaseMigrations;
use WithoutMiddleware;
public function testMethodAll()
{
$admin = factory(Role::class, 'admin')->create();
$user = $admin->users()->save(factory(User::class)->make());
$paginatedUsers = json_decode(
$this->json('GET', 'api/v1/users')
->seeStatusCode(200)
->response
->getContent(),
true
);
$paginationAndUserKeys = [
'total',
'per_page',
'current_page',
'last_page',
'next_page_url',
'prev_page_url',
'from',
'to',
'limit',
'id',
'role_id',
'first_name',
'last_name',
'username',
'email',
'company',
'created_at',
'updated_at',
'deleted_at'
];
$this->validateKeys($paginatedUsers, $paginationAndUserKeys);
$this->validateCountKeys($paginatedUsers, $paginationAndUserKeys);
}
public function testMethodCreate()
{
$faker = Faker\Factory::create();
$admin = factory(Role::class, 'admin')->create();
$this->json(
'POST',
'api/v1/users',
[
'role_id' => $admin->id,
'first_name' => $faker->firstName,
'last_name' => $faker->lastName,
'username' => $faker->userName,
'email' => $faker->email,
'password' => bcrypt('secret')
]
)
->seeStatusCode(200)
->seeJsonEquals(['success' => true]);
}
public function testMethodShow()
{
$admin = factory(Role::class, 'admin')->create();
$user = $admin->users()->save(factory(User::class)->make());
$response = json_decode(
$this->json('GET', 'api/v1/users/' . $user->id)
->seeStatusCode(200)
->response
->getContent()
);
$this->assertEquals($response->role_id, $user->role_id);
$this->assertEquals($response->first_name, $user->first_name);
$this->assertEquals($response->last_name, $user->last_name);
$this->assertEquals($response->username, $user->username);
$this->assertEquals($response->email, $user->email);
}
public function testMethodUpdate()
{
$faker = Faker\Factory::create();
$admin = factory(Role::class, 'admin')->create();
$user = $admin->users()->save(factory(User::class)->make());
$newValues = [
'first_name' => $faker->firstName,
'last_name' => $faker->lastName,
'username' => $faker->userName,
'email' => $faker->email,
'password' => $faker->password
];
$this->json('PUT', 'api/v1/users/' . $user->id, $newValues)
->seeStatusCode(200)
->seeJsonEquals(['success' => true]);
$updated_user = User::find($user->id);
$this->assertEquals($updated_user->first_name, $newValues['first_name']);
$this->assertEquals($updated_user->last_name, $newValues['last_name']);
$this->assertEquals($updated_user->username, $newValues['username']);
$this->assertEquals($updated_user->email, $newValues['email']);
$this->assertTrue(
password_verify(
$newValues['password'],
$updated_user->password
)
);
}
public function testMethodDelete()
{
$admin = factory(Role::class, 'admin')->create();
$user = $admin->users()->save(factory(User::class)->make());
$this->json('DELETE', 'api/v1/users/' . $user->id)
->seeStatusCode(200)
->seeJsonEquals(['success' => true]);
$this->assertEquals(User::find($user->id), null);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment