I'm writing tests and I want to assert, that a returned collection has some specific structure.
For asserting json
s I'm using assertJsonStructure()
method on the Responce
object.
I have not found similar for the \Illuminate\Support\Collection
. Did I miss some package/framework method.
An example of what do I want
$collection = collect([
'name' => 'John',
'surname' => 'Smith',
'birthoday' => [
'day' => 23,
'month' => 5,
'year' => 1970,
],
]);
$collection->assertStructure([ //true
'name',
'surname',
'birthday' => ['day', 'month', 'year'],
]);
I will accept
no
as an answer too, but if it is with an example of how to validate such a nested collection.
There is no such function on Collection instance, the closest you can do are:
has()
contains()
If you need inspiration, you can get it with the way Laravel implements assertJsonStructure()
in /Illuminate/Foundation/Testing/TestResponse.php
:
/**
* Assert that the response has a given JSON structure.
*
* @param array|null $structure
* @param array|null $responseData
* @return $this
*/
public function assertJsonStructure(array $structure = null, $responseData = null)
{
if (is_null($structure)) {
return $this->assertJson($this->json());
}
if (is_null($responseData)) {
$responseData = $this->decodeResponseJson();
}
foreach ($structure as $key => $value) {
if (is_array($value) && $key === '*') {
PHPUnit::assertInternalType('array', $responseData);
foreach ($responseData as $responseDataItem) {
$this->assertJsonStructure($structure['*'], $responseDataItem);
}
} elseif (is_array($value)) {
PHPUnit::assertArrayHasKey($key, $responseData);
$this->assertJsonStructure($structure[$key], $responseData[$key]);
} else {
PHPUnit::assertArrayHasKey($value, $responseData);
}
}
return $this;
}
As you can see there is a recursive calls to check the structure in case there is sub-structure.
UPDATE:
As a basic test to solve your question, I modified the assertJsonStructure()
to have assertArrayStructure()
and this working test:
/**
* A basic test example.
*
* @return void
*/
public function testBasicTest()
{
$collect = collect(['name' => '1', 'detail' => ['age' => 1,'class' => 'abc']]);
$this->assertArrayStructure(['name', 'detail' => ['class', 'age']], $collect->toArray());
}
/**
* Assert the array has a given structure.
*
* @param array $structure
* @param array $arrayData
* @return $this
*/
public function assertArrayStructure(array $structure, array $arrayData)
{
foreach ($structure as $key => $value) {
if (is_array($value) && $key === '*') {
$this->assertInternalType('array', $arrayData);
foreach ($arrayData as $arrayDataItem) {
$this->assertArrayStructure($structure['*'], $arrayDataItem);
}
} elseif (is_array($value)) {
$this->assertArrayHasKey($key, $arrayData);
$this->assertArrayStructure($structure[$key], $arrayData[$key]);
} else {
$this->assertArrayHasKey($value, $arrayData);
}
}
return $this;
}
The answer is no, you can simply look for assertive laravel methods at the API documentation, there is no method at the namespace Illuminate\Support\Collection
which makes what you are looking for. (You can find Laravel assertive method here)
As a viable alternative, why you don't just serialize your collection and check it with the assertJsonStructure()
method?
You could use the response()
helper to populate a Illuminate/Foundation/Testing/TestResponse
:
use Illuminate/Foundation/Testing/TestResponse;
$testResponse = new TestResponse(response()->json($collection->toArray());
return $testResponse->assertJsonStructure([
'name',
'surname',
'birthday' => ['day', 'month', 'year'],
]);
How I came to this solution:
$this->json()
in a test, which comes from the trait MakesHttpRequests
right here.Illuminate\Foundation\Testing\TestResponse
.Illuminate/Http/Response
.Hope this helps you.